
在 go 中,接收器是方法所属的类型实例(类似其他语言的 `this` 或 `self`),而参数是显式传入的值;接收器决定方法归属和调用绑定方式,参数仅用于传递数据。二者在语义、作用域和绑定时机上存在根本差异。
在 Go 的面向对象设计中,“方法”并非独立函数,而是依附于特定类型的函数。其语法结构为:
func (r ReceiverType) MethodName(params...) ReturnType { ... }其中 (r ReceiverType) 是接收器声明,它既指明了该方法可被哪个类型(或其指针)调用,也定义了方法内部访问该类型字段和方法的上下文。而 params... 是参数列表,仅用于接收调用时传入的额外数据。
接收器:隐式、结构性、绑定型
接收器在调用时不显式写出,而是通过点号语法体现:
p := &Page{Title: "Home", Body: []byte("Hello")}
err := p.save() // ✅ 正确:p 是接收器,save 无参数此处 p 就是接收器——它决定了:
- 方法属于 *Page 类型(而非 Page 或其他类型);
- 方法体内可通过 r.Title、r.Body 直接访问字段(r 即接收器变量名);
- 若接收器是接口类型(如 func (s Stringer) String() string),则实际调用的方法由运行时动态确定(即支持多态)。
参数:显式、数据性、静态传递
参数始终出现在方法签名括号内,调用时必须按序提供:
func (p *Page) saveWithBackup(backupDir string) error {
if err := p.save(); err != nil {
return err
}
return ioutil.WriteFile(filepath.Join(backupDir, p.Title+".bak"), p.Body, 0600)
}
// 调用时需显式传参:
err := p.saveWithBackup("/tmp/backups")
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 参数(必须提供)注意:参数值在调用时被复制传递(即使是结构体或切片,也是复制其头部信息),而接收器若为指针(如 *Page),则方法内可直接修改原始值。
关键区别总结
| 维度 | 接收器 | 参数 |
|---|---|---|
| 语法位置 | 方法名前括号内(func (r T)) | 方法名后括号内(func(...)) |
| 调用体现 | 隐式:x.f() 中的 x | 显式:f(a,b) 中的 a,b |
| 语义角色 | “谁在执行这个操作?”(主体/所有者) | “操作需要哪些额外信息?”(输入) |
| 绑定时机 | 编译期静态绑定类型(除非是接口接收器) | 纯数据传递,无类型行为绑定 |
| 内存影响 | 指针接收器可修改原值;值接收器仅操作副本 | 总是传值(包括 slice/map/chan 的 header) |
⚠️ 注意:不要将接收器误认为“第一个参数”。虽然底层实现可能类似,但 Go 明确区分二者——接收器参与方法集(method set)构建、接口实现判定及嵌入提升(embedding promotion),而参数完全不参与这些机制。
掌握这一区别,是写出符合 Go 惯例、类型安全且可扩展代码的基础。








