Go 語言 在近期內會推出 1.18  版本,而 1.18 最重要的功能之一就是 generics ,在此版本之前,最令人詬病的就是 Go 無法支援多種 Type 當參數,造成在寫 Package 時候多出很多重複性的程式碼,本篇會教大家基礎認識什麼是 generics,及怎麼使用。
影片教學 VIDEO 
影片視頻會同步放到底下課程內
安裝 1.18 及整合 Vscode 編輯器 首先要先安裝 go1.18 beta2  版本,方式很簡單,請參考底下
1 
2 
go install golang.org/dl/go1.18beta2@latest
 go1.18beta2 download
 
完成後可以透過底下指令看到 go1.18beta2
1 
2 
$ go1.18beta2 env GOROOT
 /Users/mtk10671/sdk/go1.18beta2
 
如果要快速嘗試用 go 指令,可以直接透過 alias 指令
該如何整合到 Vscode 內呢?請參考這篇文章 ,幾個步驟就可以完成。第一個步驟就是請把 go1.18beta2 變成環境變數預設值 PATH,請改成
1 
PATH =" $HOME /sdk/go1.18beta2/bin: $PATH " 
打開 VSCODE 編輯器,重新安裝全部 tools ,直接 cmd + shift + p 選擇 Go: Install/Update Tools,把全部 toll 打勾重新安裝。最後步驟就是打開預設的 config.json 檔案加上
1 
2 
3 
"gopls" :  {
  "ui.semanticTokens" : true 
 }
 
使用 generic 我們來寫一個 func 支援一個參數,此參數可以是 int64 或 float64 型態,線上執行 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
package  main
 import  "fmt" 
 func  show[num int64  | float64 ](s num) {
  fmt.Println (s)
 }
 
 func  main () {
  fmt.Println ("go 1.18 Generics Example" )
 
   var  sum1 int64  = 28 
   var  sum2 float64  = 29.5 
 
   show (sum1)
   show (sum2)
 }
 
大家可以看到 [num int64 | float64] 定義一個新的型態,此型態可以為 int64 或 float64,再把這型態放到後面。不過如果支援型態很多的話,可以改寫如下,線上執行 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
package  main
 import  "fmt" 
 type  age interface  {
  int8  | int16  | int32  | int64  | float32  | float64 
 }
 
 func  show[num age](s1 num) {
  val := float64 (s1) + 1 
   fmt.Println (val)
 }
 
 func  main () {
  fmt.Println ("go 1.18 Generics Example" )
 
   var  sum1 int64  = 28 
   var  sum2 float64  = 29.5 
 
   show (sum1)
   show (sum2)
 }
 
在程式碼內定義一個新的 interface 將所有型態放入即可
1 
2 
3 
type  age interface  {
  int8  | int16  | int32  | int64  | float32  | float64 
 }
 
如果要支援多個參數可以怎麼寫
1 
2 
3 
4 
func  total[num age](s1, s2 num) {
  val := float64 (s1) + float64 (s2)
   fmt.Println (val)
 }
 
這樣就可以同時帶入兩個一樣的參數型態。如果要帶入不同的型態,第一個參數是 int64,第二個是 float64,請改成如下
1 
2 
3 
4 
func  summary[num1, num2 age](s1 num1, s2 num2) {
  val := float64 (s1) + float64 (s2)
   fmt.Println (val)
 }
 
完整測試程式碼可以參考底下,線上執行 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
package  main
 import  "fmt" 
 type  age interface  {
  int8  | int16  | int32  | int64  | float32  | float64 
 }
 
 func  newGenerics[num age](s1 num) {
  val := float64 (s1) + 1 
   fmt.Println (val)
 }
 
 func  total[num age](s1, s2 num) {
  val := float64 (s1) + float64 (s2)
   fmt.Println (val)
 }
 
 func  summary[num1, num2 age](s1 num1, s2 num2) {
  val := float64 (s1) + float64 (s2)
   fmt.Println (val)
 }
 
 func  main () {
  fmt.Println ("go 1.18 Generics Example" )
 
   var  sum1 int64  = 28 
   var  sum2 float64  = 29.5 
 
   newGenerics (sum1)
   newGenerics (sum2)
 
   var  sum3 float64  = 28 
   var  sum4 float64  = 29.5 
 
   total (sum3, sum4)
 
   var  sum5 int64  = 28 
   var  sum6 float64  = 29.5 
 
   summary (sum5, sum6)
 }
 
最後我們來看一個例子泡沫排序 (Bubble sort )
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
package  main
 import  "fmt" 
 // conver to generics type to support int and float64 types
 func  bubbleSort (array []int ) []int  {
  for  i := 0 ; i < len (array)-1 ; i++ {
     for  j := 0 ; j < len (array)-i-1 ; j++ {
       if  array[j] > array[j+1 ] {
         array[j], array[j+1 ] = array[j+1 ], array[j]
       }
     }
   }
   return  array
 }
 
 func  main () {
  array := []int {11 , 14 , 3 , 8 , 18 , 17 , 43 }
   fmt.Println (bubbleSort (array))
 }
 
除了支援 int 之外,也請支援 float64。請直接看底下解答,線上執行 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
package  main
 import  "fmt" 
 // The Time Complexity of the Bubble Sort is O(n^2) since it takes two nested loops to check the adjacent element.
 // For example, let’s take the following unsorted array −
 // 22 15 11 45 13
 // Bubble Sort Algorithm first traverses the whole array and then in another loop checks if the adjacent elements are in order or not.
 // Thus, after sorting the elements will be,
 // 11 13 15 22 45
  
// conver to generics type to support both int and float64 types
  
type  Number interface  {
  int  | int32  | int64  | float32  | float64 
 }
 
 func  bubbleSort[n Number](array []n) []n {
  for  i := 0 ; i < len (array)-1 ; i++ {
     for  j := 0 ; j < len (array)-i-1 ; j++ {
       if  array[j] > array[j+1 ] {
         array[j], array[j+1 ] = array[j+1 ], array[j]
       }
     }
   }
   return  array
 }
 
 func  main () {
  n1 := []int {11 , 14 , 3 , 8 , 18 , 17 , 43 }
   fmt.Println (bubbleSort (n1))
   n2 := []float64 {11.1 , 14.2 , 3.3 , 8.4 , 18.5 , 17.6 , 43.7 }
   fmt.Println (bubbleSort (n2))
 }
 
心得 終於有機會可以優化一些 Package 的寫法,不過為了向下相容,原本的 go1.17 寫法還是會保留,透過 go build tag 方式來決定不同的使用環境即可。
See also