Go方法集
方法集决定类型是否能满足特定接口,理解方法集是掌握接口的关键。
方法集定义
值类型方法集
Go
type User struct {
Name string
}
// 值接收者方法
func (u User) GetName() string {
return u.Name
}
// 指针接收者方法
func (u *User) SetName(name string) {
u.Name = name
}
// 值类型User的方法集:只有值接收者方法
// User的方法集:{GetName}
指针类型方法集
Go
// 指针类型*User的方法集:包含所有方法
// *User的方法集:{GetName, SetName}
// 指针类型包含值接收者和指针接收者方法
方法集规则
核心规则
Go
类型T的方法集 = 所有接收者为T的方法
类型*T的方法集 = 所有接收者为T和*T的方法
规则详解
Go
type MyType struct{}
func (m MyType) ValueMethod() {} // 值接收者
func (m *MyType) PointerMethod() {} // 指针接收者
// MyType方法集:{ValueMethod}
// *MyType方法集:{ValueMethod, PointerMethod}
接口满足规则
值类型与接口
Go
type Reader interface {
Read() string
}
type MyReader struct{}
func (m MyReader) Read() string {
return "data"
}
// MyReader有值接收者方法Read
// MyReader满足Reader接口 ✓
// *MyReader也满足Reader接口 ✓
var r Reader = MyReader{} // ✓
var r Reader = &MyReader{} // ✓
指针接收者方法
Go
type Writer interface {
Write(data string)
}
type MyWriter struct{}
func (m *MyWriter) Write(data string) {
// 指针接收者方法
}
// MyWriter方法集:{}(空)
// *MyWriter方法集:{Write}
// MyWriter不满足Writer接口 ✗
// *MyWriter满足Writer接口 ✓
var w Writer = MyWriter{} // ✗ 编译错误
var w Writer = &MyWriter{} // ✓
方法集对比表
| 接收者类型 | T方法集 | *T方法集 | T满足接口 | *T满足接口 |
|---|---|---|---|---|
| 值接收者 | ✓ | ✓ | ✓ | ✓ |
| 指针接收者 | ✗ | ✓ | ✗ | ✓ |
| 混合 | 值方法 | 全部 | 值接口 | 全部 |
方法集陷阱
指针接收者导致值不满足接口
Go
type Interface interface {
Method()
}
type Impl struct{}
func (i *Impl) Method() {} // 指针接收者
// 错误:值不满足接口
var x Interface = Impl{} // 编译错误!
// 正确:指针满足接口
var x Interface = &Impl{} // OK
解决方案
Go
// 方案1:使用指针
var x Interface = &Impl{}
// 方案2:改为值接收者
func (i Impl) Method() {} // 值接收者
// 方案3:同时实现两种接收者
func (i Impl) Method() {} // 值接收者
func (i *Impl) Method() {} // 指针接收者(冗余)
方法集示例
Go
type Calculator interface {
Calculate() int
Reset()
}
type MyCalc struct {
value int
}
func (m MyCalc) Calculate() int {
return m.value // 值接收者
}
func (m *MyCalc) Reset() {
m.value = 0 // 指针接收者
}
// MyCalc方法集:{Calculate}
// *MyCalc方法集:{Calculate, Reset}
// MyCalc不满足Calculator接口(缺少Reset)
// *MyCalc满足Calculator接口
var c Calculator = &MyCalc{} // ✓
// var c Calculator = MyCalc{} // ✗
接口赋值规则
自动转换规则
text
type T struct{}
func (t T) M1() {} // 值接收者
func (t *T) M2() {} // 指针接收者
var t T
var p = &t
// 调用方法时自动转换
t.M1() // ✓ 值调用值方法
t.M2() // ✓ 值调用指针方法(自动转为(&t).M2())
p.M1() // ✓ 指针调用值方法(自动转为(*p).M1())
p.M2() // ✓ 指针调用指针方法
// 但接口赋值不自动转换
// var i Interface = T{} // 需要T方法集包含全部方法
要点总结
- T方法集 = 值接收者方法
- *T方法集 = 值接收者 + 指针接收者方法
- 指针接收者方法:值类型不满足接口
- 值接收者方法:值和指针都满足接口
- 方法调用时自动转换,接口赋值不转换
- 使用指针接收者时,接口赋值需用指针
- 混合接收者时,指针类型方法集更完整
📝 发现内容有误?点击此处直接编辑