Go語言的泛型(generics)簡介。
簡介
Go未加入泛型以前函式的參數只能有一型態,雖然空介面參數或實作介面參數能達到參數多樣(多型polymorphism)的效果但有些不足。空介面參數要先轉型且無法做編譯檢查;實作介面參數的類型必須實作每一個介面方法非常不便。Go 1.18加入泛型後讓函式的參數型態可為多樣且編譯時檢查型態避免執行期發生錯誤。
範例
Go透過在函式名稱後定義type parameters來達到泛型效果。下面的Add()
即為定義泛型型態的泛型函式(generic function)。
函式Add()
的名稱與參數間的方括弧敘述([T int | float64]
)為泛型定義,T
為type parameter,int | float64
為type constraints,意思是type parameter T
的型態只能是int
或float64
。
呼叫泛型函式時在函式名稱與引數間指定引數的泛型型態稱為type arguments,只有符合型態的引數才能傳入。例如下面的Add[int](1, 2)
的[int]
即是type argument;Add[float64](1.1, 2.2)
的type argument為float64
。或呼叫時由引數的型態來推斷則可省略type arguments的敘述,例如下面的Add(1, 2)
及Add(1.1, 2.2)
皆省略了type argument。
main.go
package main
import "fmt"
func main() {
// call generic function with type arguments
fmt.Println(Add[int](1, 2)) // 3
fmt.Println(Add[float64](1.0, 2.2)) // 3.2
// call generic function without type arguments
fmt.Println(Add(1, 2)) // 3
fmt.Println(Add(1.0, 2.2)) // 3.2
}
func Add[T int | float64](x, y T) T {
return x + y
}
Type constraints也可抽出另外定義為interface。例如下面把Add()
函式的type constraints改定義在interface Num
,則type parameter T
的constraint改為Num
。
main.go
package main
import "fmt"
type Num interface {
int | float64 // type constraints
}
func main() {
// call generic function with type arguments
fmt.Println(Add[int](1, 2)) // 3
fmt.Println(Add[float64](1.0, 2.2)) // 3.2
// call generic function without type arguments
fmt.Println(Add(1, 2)) // 3
fmt.Println(Add(1.0, 2.2)) // 3.2
}
func Add[T Num](x, y T) T {
return x + y
}
Generic的interface constraint可用來定義generic type的slice。注意下面var ints Nums[int]
的[int]
是type arguments,覺得應該和呼叫函式一樣可自行推斷才是。
PrintMap()
函式的type constraint comparable
代表「非interface的可比較型態」,即任何可用=
和!=
運算符比較的型態皆屬於comparable
,如int
、string
。
main.go
package main
import "fmt"
type Num interface {
int | float64 // type constraints
}
type Nums[T Num] []T // slice of generic type
func main() {
var ints Nums[int] = []int{1, 2, 3}
PrintAll[int](ints)
var floats Nums[float64] = []float64{1.1, 2.2, 3.3}
PrintAll(floats)
m := map[string]Nums[int]{
"a": {1, 2},
"b": {3, 4},
}
PrintMap(m)
}
func PrintAll[T Num](nums Nums[T]) {
for _, n := range nums {
fmt.Println(n)
}
}
func PrintMap[K comparable, V Num](m map[K]Nums[V]) {
for k, v := range m {
fmt.Printf("key=%v, value=%v\n", k, v)
}
}
沒有留言:
張貼留言