函数与方法
声明与调用
go
func Add(a, b int) int {
return a + b
}
多返回值惯用 (T, error),调用方可忽略部分返回值(编译器可能对未使用报错,取决于是否为 _)。
变参
末参数可为 ...T,函数内为 []T:
go
func Sum(nums ...int) int {
s := 0
for _, n := range nums {
s += n
}
return s
}
展开切片:Sum(slice...)。
命名返回值
go
func Split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return // 裸 return,返回已命名的 x, y
}
滥用会降低可读性;短函数或消除重复 return 变量名时较合适。
闭包
函数值可捕获外层变量,注意捕获的是变量本身(在 1.22 前与循环变量结合时易错;1.22 后循环变量语义已变,仍建议显式传参以降低心智负担):
go
func makeAdder(base int) func(int) int {
return func(delta int) int {
base += delta
return base
}
}
方法
带接收者的函数:func (r Receiver) M() 或 func (r *Receiver) M()。
值接收者 vs 指针接收者
| 值接收者 | 指针接收者 |
|---|---|
| 拷贝接收者,大结构体成本高 | 不拷贝整个结构体 |
| 不能通过方法修改原字段(改的是副本) | 可修改原实例 |
nil 指针值接收者调用会 panic(对指针解引用) | 常见允许 nil 接收者,在方法内判空 |
一致性:同一类型方法集建议统一指针或值接收者,避免混用令调用者困惑。
方法集(Method sets)
接口 satisfied 时,值 T 的方法集含值接收者方法;*T 的方法集含值与指针接收者方法。将 T 赋给接口时,仅 T 的方法集可用;将 *T 赋给接口时两者皆可(规范中的 promotion 规则)。
递归
与多数语言相同;注意栈深度与尾递归未做特殊优化。
init
每个包可有多个 func init(),在 main 之前、导入依赖初始化之后按依赖顺序执行;勿写复杂逻辑或依赖顺序难控的副作用。