泛型本质是编译期类型契约,需带约束而非简单用[T any];~int支持底层为int的别名;类型推导常失效,需显式指定类型参数;泛型结构体方法接收器必须含[T]。

泛型不是加个 [T any] 就能跑通的语法糖,它本质是编译期类型契约——约束写错、推导失效、方法签名漏参数,三者叠加就能让代码卡在编译阶段。
泛型函数必须带约束,[T any] 不等于“随便传”
很多人一上来就写 func Do[T any](x T),结果发现 x == y 报错、len(x) 不支持、x.String() 找不到方法。这是因为 any 只表示“任何类型”,不提供任何操作能力。
- 需要比较(
==/!=):必须用[T comparable] - 需要排序或大小比较(
/ <code>>):得用constraints.Ordered(需导入golang.org/x/exp/constraints) - 需要调用方法:约束必须包含该方法签名,比如
type Stringer interface{ String() string },再写[T Stringer] - 需要数值运算:别硬套
any,定义type Number interface{ ~int | ~float64 }更稳
~int 和 int 在约束里完全不是一回事
如果你定义了 type Millis int,然后写 func F[T int](x T),那传 Millis(100) 会直接报错:“cannot use Millis(100) as T value in argument to F”。因为 int 只匹配 int 本身,不认别名。
-
~int表示“底层类型为int的所有类型”,包括Millis、Seconds这类自定义单位类型 -
~只能用于基本类型:~string、~bool合法;~struct{}或~map[string]int是语法错误 - 数组、切片、map 等复合类型不能加
~,只能靠具体类型或接口约束
类型推导经常失效,显式写出类型参数不是妥协,是必要
Go 编译器只在参数类型完全一致时才自动推导泛型类型。以下情况都会推导失败:
立即学习“go语言免费学习笔记(深入)”;
-
Max(1, 3.14):1 是int,3.14 是float64,没有共同的T -
F(nil):nil 没有类型信息,必须写成F[*int](nil)或F[User](nil) -
make([]T, 0)中的T无法从上下文推出,尤其当函数参数也是泛型且无实参时
解决办法很直接:遇到推导失败,立刻显式写出类型参数。例如 Max[int](1, 2)、Stack[string]{}、MapKeys[int, string](m)。这不是啰嗦,是给编译器明确信号。
泛型结构体的方法签名必须带类型参数
这是最容易被忽略的细节:泛型结构体的方法接收器必须带上类型参数,否则 T 在方法体内就是未定义的。
- 正确:
func (s *Stack[T]) Push(item T) - 错误:
func (s *Stack[T]) Push(item interface{})(失去类型安全) - 错误:
func (s *Stack) Push(item T)(T未声明)
同样,初始化也不能只写 Stack{},必须指定类型:Stack[int]{} 或 var s Stack[string]。泛型结构体不是模板,而是编译时生成的具体类型,Stack[int] 和 Stack[string] 完全不兼容。



















