泛型
2026年9月6日
Go 1.18 加上了类型参数。以前给 int 写一个求和,float64、int32 就得再抄一份。泛型让同一套逻辑套在一组类型上。
泛型函数
func Sum[T int | int32 | int64 | float64](nums ...T) T {
var s T
for _, n := range nums {
s += n
}
return s
}
fmt.Println(Sum(1, 2, 3))
fmt.Println(Sum(1.5, 2.5))
go
T 是类型参数,int | int32 | ... 是约束:这些类型都能做 +。约束也能写成接口:
type Number interface {
int | int32 | int64 | float64
}
func Sum[T Number](nums ...T) T { /* ... */ }
go
标准库 cmp.Ordered、constraints.Integer 把常见集合收好了。任意类型用 any;要能比较用 comparable。
调用时多数情况不用写 [int],编译器会推断。
泛型结构体
type Box[T any] struct {
Val T
}
func (b Box[T]) Get() T {
return b.Val
}
n := Box[int]{Val: 3}
s := Box[string]{Val: "槿"}
go
方法必须挂在已经带类型参数的接收者上,不能给 Box 再声明一套不带 T 的方法。
泛型切片
func Map[T, U any](s []T, f func(T) U) []U {
out := make([]U, len(s))
for i, v := range s {
out[i] = f(v)
}
return out
}
fmt.Println(Map([]int{1, 2}, func(n int) string {
return fmt.Sprintf("#%d", n)
}))
go
slices.Clone、slices.Contains 就是这种写法。
泛型 map
func Keys[K comparable, V any](m map[K]V) []K {
keys := make([]K, 0, len(m))
for k := range m {
keys = append(keys, k)
}
return keys
}
go
map 的 key 必须 comparable。maps.Keys、maps.Clone 已经在标准库里。
能用具体类型写清楚的,不必硬上泛型。类型参数是为了少复制、又保住编译期检查。