函数与方法
多返回值、方法接收者,以及值/指针接收者的直觉。
函数声明
func add(a int, b int) int {
return a + b
}
// 同类型参数可合并
func add2(a, b int) int {
return a + b
}
可变参数:
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
sum(1, 2, 3)
sum([]int{1, 2}...) // 展开 slice
函数也是值,可赋给变量、作参数。
多返回值与命名返回
func div(a, b int) (int, error) {
if b == 0 {
return 0, fmt.Errorf("division by zero")
}
return a / b, nil
}
q, err := div(10, 2)
if err != nil {
// ...
}
命名返回值:在签名里起名,可用裸 return:
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return // 返回 x, y
}
入门阶段:错误用 (T, error);命名返回适可而止,避免影响可读性。错误处理细节见进阶「错误处理」。
方法:接收者
方法是带接收者的函数:
type Counter struct {
n int
}
func (c Counter) Value() int { // 值接收者
return c.n
}
func (c *Counter) Inc() { // 指针接收者
c.n++
}
var c Counter
c.Inc()
fmt.Println(c.Value()) // 1
调用时 Go 会自动取址/解引用:c.Inc() 等价 (&c).Inc()。
值接收者 vs 指针接收者
| 选择 | 典型动机 |
|---|---|
| 值接收者 | 小对象、只读、不想暴露可变性 |
| 指针接收者 | 要改接收者;大结构体避免拷贝;与接口方法集一致 |
约定:同一类型的方法接收者尽量统一(都用指针或都用值),减少心智负担。
type Buf struct {
data []byte
}
func (b *Buf) Append(p []byte) {
b.data = append(b.data, p...)
}
若类型需要实现某接口且接口方法是指针接收者,则只有 *T 实现该接口(进阶「接口与组合」)。
小结
- 多返回值是惯用错误通道:
(result, error) - 方法 = 函数 + 接收者
- 要改状态 / 大对象 → 指针接收者
- 同一类型接收者风格保持一致