✅ 一、什么是接收者?
在 Go 中,没有类(class)和对象(object)的概念 ,但可以通过 struct 和 方法(method) 实现类似面向对象的功能。
而"接收者"就是用来定义:"这个方法是谁的"。
🔹 语法结构:
func (接收者变量 接收者类型) 方法名(参数列表) 返回值 {
// 方法体
}
例如:
type Dog struct {
Name string
}
// 这里的 `d *Dog` 就是接收者
func (d *Dog) Bark() {
fmt.Println(d.Name, "在叫:汪汪!")
}
d:接收者变量名(你可以叫它dog,t,self等)*Dog:接收者类型(可以是指针或值)Bark():方法名
调用时:
dog := &Dog{Name: "旺财"}
dog.Bark() // 输出:旺财 在叫:汪汪!
✅ 二、接收者的两种形式
|----------|------------|--------------|
| 类型 | 写法 | 含义 |
| 🟢 值接收者 | (d Dog) | 方法操作的是该类型的副本 |
| 🔵 指针接收者 | (d *Dog) | 方法操作的是原始对象本身 |
示例对比:
type Person struct {
Name string
}
// 值接收者:只能读,不能改原对象
func (p Person) SetNameByValue(name string) {
p.Name = name // 修改的是副本!
}
// 指针接收者:可以直接修改原对象
func (p *Person) SetNameByPointer(name string) {
p.Name = name // 真正修改了原对象
}
测试代码:
go
编辑
func main() {
person := Person{Name: "小明"}
person.SetNameByValue("小红")
fmt.Println(person.Name) // 输出:小明 ❌ 没变!
person.SetNameByPointer("小蓝")
fmt.Println(person.Name) // 输出:小蓝 ✅ 改了!
}
💡 因为值接收者传入的是拷贝,所以改不动原数据。
✅ 三、为什么需要接收者?
Go 不像 Java/C++ 那样有 this 或 self 关键字。接收者的作用就是:
- 明确指定某个方法属于哪个类型
- 让该类型的所有实例都可以调用这个方法
- 实现"封装"和"多态"
就像你说"狗会叫",那么 Bark() 方法就应该属于 Dog 类型。
✅ 四、接收者的常见写法风格
go
编辑
func (d Dog) Eat() {} // d 是 Dog 的一个副本
func (d *Dog) Run() {} // d 是指向 Dog 的指针
func (p *Person) GetName() string { return p.Name }
命名建议:
- 单个字母即可,如
d,p,s - 一般用类型首字母小写,比如
dog,person→(dog *Dog) - 不要用
self或this(不是 Python/JavaScript)
✅ 五、自动解引用机制(重要!)
Go 很智能,允许你混用:
go
编辑
dog := Dog{Name: "花花"}
ptr := &dog
dog.Run() // Run 是 *Dog 方法?没关系,Go 自动转成 (&dog).Run()
ptr.Eat() // Eat 是 Dog 方法?也没关系,Go 自动转成 (*ptr).Eat()
✅ 所以你在调用方法时,不用关心它是值接收者还是指针接收者,Go 会自动处理。
⚠️ 但在 接口赋值 时就有区别了(见下文)。
✅ 六、接收者与接口的关系(关键!)
假设你有一个接口:
go
编辑
type Animal interface {
Move()
}
如果你这样实现:
go
编辑
func (a *AnimalImpl) Move() {}
那么只有 *AnimalImpl 实现了接口,AnimalImpl 本身没有实现!
所以以下代码会报错:
go
编辑
var a Animal = AnimalImpl{} // ❌ 错误!AnimalImpl 没有实现 Move()
正确写法:
go
编辑
var a Animal = &AnimalImpl{} // ✅ 正确
👉 因此:如果要用类型实现接口,推荐统一使用指针接收者。
✅ 七、什么时候用值接收者?什么时候用指针接收者?
|-----------------|----------------|
| 场景 | 推荐 |
| 方法要修改字段 | ✅ 必须用指针接收者 |
| 结构体较大(> 几十个字节) | ✅ 用指针接收者(避免拷贝) |
| 只读操作、小型结构体 | 可用值接收者 |
| 实现接口 | 推荐用指针接收者 |
| 不确定时 | 用指针接收者更安全 |
✅ 总结
|-------------------------|------------------------------------------|
| 问题 | 回答 |
| 什么是接收者? | 定义"这个方法是谁的"的语法结构 |
| 写法是什么? | func (变量 类型) 方法名(...) |
| 加 ***** 和不加的区别? | 是否能修改原对象、是否拷贝数据 |
| 应该用哪个? | 修改字段 → 用 *T ;只读 → 可用 T ;接口 → 推荐 *T |
| 为什么重要? | 是 Go 实现"面向对象"的核心机制之一 |
💡 一句话记住:
接收者就是 Go 的 this 或 self,它让方法和类型绑定在一起,形成"行为 + 数据"的组合。
你现在完全可以把接收者理解为:"我是这个类型的成员函数"。
