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