go 泛型
1. 類型參數(shù)(Type parameters)
Go語言的泛型(Generic)叫做類型參數(shù)刀荒。泛型可以讓我們代碼適應不同類型的參數(shù)哀澈。
泛型函數(shù)
聲明語法
// 聲明一個帶有泛型的函數(shù)
// T 指類型參數(shù)础钠,就是一個參數(shù),代表類型
// Constraint 是對類型參數(shù)T的約束叫胖,限制T的取值, 可以是int棺蛛、string、any等類型巩步,any可以是任意類型的意思
// s 是要打印的參數(shù)
func name[T {Constraint}](s T) {}
函數(shù)名和函數(shù)參數(shù)列表之間插入了一組方括號旁赊,來表示類型參數(shù)。跟函數(shù)參數(shù)一樣椅野,我們需要為每一個類型參數(shù)指定「類型」终畅,這種類型的類型Go語言稱之為約束。
示例
// 打印函數(shù)
func print[T any](s ...T) {
for _, i := range s {
fmt.Println(i)
}
}
T表是切片成員的類型竟闪,但T的實際類型在定義print()的時候是不確定的离福,需要在調(diào)用該函數(shù)的時候指明。也就是說炼蛤,我們在調(diào)用print()函數(shù)的時候需要額外傳入一個特殊參數(shù)來指定T的具體類型妖爷。這種特殊的參數(shù)就叫類型參數(shù)。
使用泛型函數(shù)
func main() {
// 約束為int類型
print[int](1, 3, 4)
// 約束為string類型
print[string]("derek", "阿瓦達啃大瓜", "奇摩雞")
// 任意類型
print[any](1, "wo")
// 任意類型理朋,與any一樣
print[interface{}](1, "wo")
// 不指定約束類型絮识,則輸入的數(shù)據(jù)類型必須為同一種類型
print(1, 3, 4)
}
指定出參類型
// 指定返回參數(shù)的類型是T
func add[T any](a, b T) T {
return a + b
}
// 也可以返回指針
func addV2[T any](a T) *T {
return &a
}
func main() {
// 約束為int類型
add[int](1, 3, 4)
// 約束為string類型
add[string]("derek", "阿瓦達啃大瓜")
}
// 結果輸出:
// 8
// derek阿瓦達啃大瓜
泛型類型
// 定義一個泛型的數(shù)組
type Nums[T any] []T
// 定義一個泛型的map, map的K比較特殊嗽上,必須使用comparable來約束, 否則不生效
type Map[K comparable, V any] map[K]V
2. 內(nèi)置約束 comparable
泛型參數(shù)一般都可以進行運算操作次舌,但有兩個符號是特殊的,就是:== 和 !=兽愤。 如果參數(shù)需要使用這兩個作比較彼念,則一定要使用comparable。
// 比較兩個參數(shù)t浅萧、v是否相等
func Comp[T comparable](s []T, v T) int {
for i, t := range s {
if t == v {
return i
}
}
return 0
}
如果把上述的comparable改為any逐沙,則會報錯:
invalid operation: t == v (type parameter T is not comparable with ==)
map數(shù)據(jù)的key有需要使用comparable,否則也會報錯
3.自定義約束 (Constraint)
泛型的Constraint惯殊,可以使用any酱吝、int、string土思、comparable
都可以务热,還可以定義一個interface來定義約束
// Addable 泛型操作
type Addable interface {
// 約束類型
~int | float32 | ~float64 | string
}
func add[T Addable](a, b T) T {
return a + b
}
上述的"~"
符號不是必須的,但加上"~"
的話己儒,系統(tǒng)會兼容基類參數(shù)類型崎岂。例如,這里定義了一個類型Int
type Int int
int就是Int的基類類型闪湾,如果是這時候Addable
的是~int
冲甘,則Int會在其約束范圍內(nèi),否則不在約束范圍內(nèi)。
并集約束
取約束類型的并集江醇,int
和float32
都是約束
type Addable interface {
int | float32
}
交集約束
type Stringer interface {
String() string
}
type Addable interface {
int
Stringer
}
這種情況下濒憋,Addable
約束的類型,必須是int類型陶夜,且這個類型實現(xiàn) Stringer
接口凛驮。