Go函数签名必须显式声明参数和返回类型,不支持类型推导;多返回值需全接收或用_丢弃;指针传递本质是值传递;推荐泛型替代interface{}以提升类型安全。
Go 不支持类型推导的函数签名,func 关键字后必须紧跟着参数名、类型对,再是返回类型。漏写任意一个类型都会编译失败。
常见错误:把 func add(a, b int) int 误写成 func add(a, b) int(缺少参数类型),或 func add(a int, b int) (缺少返回类型)——后者会报 missing function body,实际是语法不完整。
a, b int 等价于 a int, b int
(int, error)
func split(x int) (a, b int))会让返回语句更简洁,但需注意:未赋值的命名返回值会取对应类型的零值Go 常用多返回值表达结果与错误(如 value, err := strconv.Atoi("42")),但语法上不允许“忽略部分返回值”——除非用 _ 显式丢弃。
容易踩的坑:直接写 strconv.Atoi("42") 而不接收返回值,编译通过但结果被丢弃;更危险的是只接收一个值,如 v := strconv.Atoi("42"),这会触发编译错误:multiple-value strconv.Atoi() in single-value context。
v, err := strconv.Atoi("42")
_, err := strconv.Atoi("42")
return(无参数),也会自动返回已命名变量的当前值Go 只有值传递。所谓“通过指针修改原变量”,本质是把地址这个整数值复制了一份传进去。因此 *T 参数能修改调用方变量内容,但无法修改其地址本身。
典型误判场景:想在函数内让外部指针指向新分配对象,却忘了必须传 **T 或返回新指针。
func updatePtr(p *int) {
newInt := 42
p = &newInt // ❌ 这里只改了形参 p 的副本,不影响调用方
}
func correctUpdate(p **int) {
newInt := 42
*p = &newInt // ✅ 修改调用方指针所存的地址
}
*Struct 参数,避免拷贝大对象interface{} 和泛型(Go 1.18+)处理不确定参数的差异旧代码常用 interface{} 模拟“任意类型”,但每次使用前需类型断言,易出 panic;Go 1.18 引入泛型后,应优先用约束更明确的类型参数。
比如实现一个通用最大值函数:Max 若用 interface{},调用时要反复断言;而用泛型 func Max[T constraints.Ordered](a, b T) T,编译期即校验类型合法性,且无运行时开销。
interface{} 适合真正动态场景(如 JSON 解析、日志打印),但务必做安全断言:v, ok := x.(string)
constraints 包(golang.org/x/exp/constraints,或 Go 1.22+ 直接用 comparable/ordered)