go函数类型必须显式定义别名,否则即使签名相同也不兼容;sort.slice的比较函数参数是索引而非元素,误传元素会导致编译错误。

函数类型必须先定义,否则编译直接报错
Go 不支持 JavaScript 那种隐式函数类型推导。哪怕两个函数签名完全一样,func(int) bool 和另一个 func(int) bool(没用同一别名)也互不兼容。你不能把一个匿名函数字面量直接塞进参数位置就完事——除非该参数类型已提前声明为具名函数类型。
常见错误现象:cannot use function value as type func(int) bool in argument to filter 或更模糊的 cannot use ... as type xxx in argument to yyy,本质都是类型不匹配。
- 必须写
type Filter func(int) bool,再用Filter作为参数类型 - 参数名无关紧要,但签名(参数个数、类型顺序、返回值类型)必须严格一致
- 别名能体现语义,比如
type Validator func(string) error比裸写func(string) error更易读、易复用、易测试
sort.Slice 的比较函数参数是索引,不是元素本身
sort.Slice 是最常踩坑的高阶函数使用场景。它的第二个参数类型是 func(i, j int) bool,传进去的函数接收的是切片下标 i 和 j,不是 users[i] 和 users[j] 本身。
典型误写:sort.Slice(users, func(a, b User) bool { return a.Age —— 编译失败,因为签名不符。
- 正确写法:在闭包内通过下标取值,如
sort.Slice(users, func(i, j int) bool { return users[i].Age - 若逻辑复杂,建议提前定义类型再复用:
type ByAge func(i, j int) bool,然后传ByAge(...) - 注意:闭包捕获的
users是引用,若原切片后续被修改,排序行为可能意外变化
传入函数可能为 nil,不检查会 panic
Go 对函数变量不做空值防护。如果调用方传了 nil,而你直接执行 filter(x),运行时就会 panic。
这在动态构造参数(比如配置驱动策略选择)、HTTP 中间件链、或泛型工具函数中尤其危险。
- 显式判空是必要卫述:
if filter == nil { return nil, errors.New("filter cannot be nil") } - 泛型版
Map[T, U any]通常也不做内部判空,因为内联后仍会 panic,所以校验责任落在调用方 - 某些场景下
nil表示“跳过”,此时应走默认分支,而非放任崩溃
返回函数时闭包捕获变量生命周期容易出错
返回 func() int 这类闭包很常见,但若它捕获了外部循环变量或大对象,行为可能和预期不符。
比如 for i := range items { go func() { fmt.Println(i) }() },所有 goroutine 最终都打印最后一个 i 值。
- 安全写法:把变量显式传入闭包,如
go func(val int) { fmt.Println(val) }(i) - 捕获局部变量(如
factor)是安全的,因为值被复制进闭包,生命周期由闭包管理 - 避免闭包持有大 struct 或长 slice,否则 GC 无法回收,内存泄漏风险高
func 关键字后面那一行。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











