泛型函数必须用方括号声明类型参数,如func Max[T any](a, b T) T,漏写方括号或位置错误会导致编译报错;[T any]仅支持基础操作,实际业务需更严格约束如comparable或Ordered;类型推断有盲区,nil、interface{}变量等场景需显式指定;泛型非interface{}替代品,仅适用于需类型安全运算或一致性校验的场景。

泛型函数必须带方括号声明类型参数,否则编译直接报错
Go 泛型函数不是“加个 T 就行”,而是语法强制要求在函数名后紧跟着 [T any] 这样的类型参数声明。漏掉方括号、空格、或把 T 放在参数列表里(比如 func Max(a, b T) T),Go 编译器会报 undefined: T —— 因为 T 根本没被声明为类型参数。
-
[T any]是最宽松的起点,但仅允许传参、返回、赋值,连==都不支持 - 函数名和方括号之间不能有空格:
func Max[T any](a, b T) T✅;func Max [T any](...)❌ - 多个类型参数用逗号分隔:
[K comparable, V any],顺序影响推导,K通常放前(如 map key)
约束决定你能写什么逻辑,[T any] 几乎写不了实际业务代码
声明 [T any] 看似万能,实则寸步难行:你无法对 T 做比较、运算、甚至不能用 fmt.Printf("%v", v) 以外的格式化(因为 %s 要求 string,而 T 不保证是字符串)。真正干活必须加约束。
-
[T comparable]→ 支持==、!=,适合去重、查找、map key -
[T constraints.Ordered](Go 1.21+ 推荐)→ 支持、<code>>、==,Max/Min/Sort类函数该用它 -
[T interface{~int | ~float64}]→ 自定义数字约束,~表示底层类型匹配,int32、int64都能过 - 别用
[T any]当兜底——它只是让你“编译通过”,不是让你“逻辑跑通”
调用时类型推断常省事,但这些情况必须显式写 [int]
多数时候 Max(1, 2) 能自动推导出 T = int,但推断机制有盲区,一旦模糊就报错,且错误信息常指向泛型定义处而非调用行,容易误判。
- 参数是
nil:Map(nil, f)必须写成Map[string, int](nil, f) - 参数来自
interface{}变量:var a, b interface{} = 1, 2; Max(a, b)会失败 - 多个类型参数且类型不明确:
Pair(nil, nil)必须写全Pair[string, int](nil, nil) - 结构体初始化也一样:
Stack[int]{}✅,Stack{}❌(报cannot use untyped composite literal)
泛型不是 interface{} 的升级版,用错场景反而更麻烦
如果你的函数只是透传、打印、序列化(比如 Log(v interface{})),硬套泛型 Log[T any](v T) 不带来任何收益:不提升类型安全(v 依然只能当 interface{} 用),还增加编译负担、降低可读性。
立即学习“go语言免费学习笔记(深入)”;
- 真该用泛型的场景很窄但明确:要对元素做
+、>、深比较,或强制类型一致性(如Map[K comparable, V any]) - 泛型结构体的字段必须用
T(data []T),不能退化成[]interface{}—— 否则就回到老路,失去类型安全 - 接收器方法也要带
[T]:func (s *Stack[T]) Push(v T),漏掉就报undefined: T
泛型的核心不是“支持任意类型”,而是“在编译期精确控制哪些类型能进来、能干什么”。约束写得松,函数就废;推导没盯住,报错就迷路;场景选错了,代码反而更重。


















