泛型

2026年9月6日

Go 1.18 加上了类型参数。以前给 int 写一个求和,float64int32 就得再抄一份。泛型让同一套逻辑套在一组类型上。


泛型函数

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.Orderedconstraints.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.Cloneslices.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 必须 comparablemaps.Keysmaps.Clone 已经在标准库里。

能用具体类型写清楚的,不必硬上泛型。类型参数是为了少复制、又保住编译期检查。


参考文档