go中只有类型的方法集,它决定接口实现、方法调用和嵌入传播:t的方法集仅含t接收者方法,t则包含t和t的所有方法;接口实现取决于静态方法集匹配,与运行时可寻址性无关。

Go里没有“类的方法集”这种说法,只有类型的方法集(Method Set)——它直接决定该类型能否赋值给某个接口、能否被指针调用、甚至能否通过嵌入传播方法。理解它不是为了背规则,而是避免编译错误和运行时行为偏差。
什么是方法集:不是所有方法都能被调用
方法集是编译器用来判断「某个类型是否实现了某个接口」或「某个表达式能否调用某方法」的依据。它不等于你写的所有方法,而取决于接收者类型:
-
T类型的方法集只包含接收者为T的方法(不含*T方法) -
*T类型的方法集包含接收者为T和*T的所有方法 - 接口类型的方法集就是它声明的所有方法
比如你定义了 func (t *Vertex) Scale(f float64),那么 Vertex{} 值不能直接调用 Scale(会报 cannot call pointer method on),但 &Vertex{} 可以;而如果还写了 func (t Vertex) Abs(),那两者都能调用 Abs。
接口实现检查:为什么 struct 满足接口,但它的字面量却不满足
常见错误:var v Vertex; var _ io.Writer = v 报错,但 var _ io.Writer = &v 成功。原因就是 io.Writer 要求实现 Write([]byte) (int, error),而你的 Write 方法接收者是 *Vertex ——所以只有 *Vertex 在方法集中有该方法,Vertex 没有。
- 接口实现是静态检查,发生在编译期,只看方法集是否匹配
- 哪怕
v是可寻址的,v.Write仍非法,因为v的方法集不含*Vertex的方法 - 反过来,如果方法接收者是
Vertex,那&v也能调用(因为*Vertex的方法集包含Vertex的方法),但修改的是副本
嵌入结构体时方法集不自动继承
嵌入(embedding)只是字段提升语法糖,不改变方法集归属。比如:
type Reader struct{ io.Reader }
func (r *Reader) Close() error { return nil }
此时 Reader 类型的方法集只有 Close;它并不自动获得 io.Reader 的 Read 方法——除非 io.Reader 字段本身是 io.Reader 接口类型(即已实现),否则你得显式转发:
- 若嵌入的是具体类型(如
struct{ bufio.Reader }),则其方法不会进入外层类型的方法集,需手动包装 - 若嵌入的是接口(如
struct{ io.Reader }),且该字段非 nil,则调用r.Read会动态分发到字段值的方法上,但这和方法集无关 - 嵌入结构体指针(
*bufio.Reader)也一样:不扩展外层类型的方法集,只提供字段访问便利
容易被忽略的边界:interface{} 和泛型约束中的方法集
interface{} 没有方法,所以任何类型都满足它,但它不参与方法集推导;而泛型约束中用接口做约束时,方法集决定实参能否代入:
-
func f[T io.Writer](t T):要求传入的t类型必须满足io.Writer接口,即其方法集必须包含Write - 若你传
Vertex{},而Write方法接收者是*Vertex,就会编译失败 - 注意:即使
Vertex值可以取地址(&v合法),也不代表v满足该约束——约束检查只看类型本身的方法集,不看运行时是否可寻址
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











