Go结构体嵌入值类型时指针接收者提升方法可调用原因问询
问题原因解答
你观察到的现象和Go官方的方法提升规则并不冲突,这是Go的方法调用语法糖导致的,具体逻辑如下:
1. 首先确认方法集规则的适用场景
你引用的结构体嵌入方法提升规则完全正确:
若S包含嵌入字段T,则S和*S的方法集均包含接收者为T的提升方法;S的方法集还包含接收者为T的提升方法。
值类型type2的方法集确实不包含接收者为*type1的type1Meth2方法,这个规则主要在接口实现校验的场景下生效,比如你执行下面的代码会直接编译报错:
type MyInterface interface { type1Meth2() } func main() { var i MyInterface = type2{} // 编译报错:type2 does not implement MyInterface (type1Meth2 method has pointer receiver) }
2. 直接调用成功的核心原因
Go在处理普通方法调用(非接口赋值场景)时,有额外的自动寻址语法糖规则:
如果调用方法的变量是可寻址的,且该变量的指针类型的方法集包含被调用的方法,编译器会自动为变量插入取地址操作,无需手动写
&。
对应你代码中(A)处的调用,编译器的处理步骤如下:
- 首先解析
type1是type2的嵌入字段,将t2.type1Meth2()自动转换为嵌入字段的方法调用t2.type1.type1Meth2() - 你的
t2是局部变量,属于可寻址的值,它的嵌入成员t2.type1也可寻址 - 因为
*type1的方法集包含type1Meth2,编译器自动插入取地址操作,最终执行的是(&t2.type1).type1Meth2(),所以调用完全合法。
3. 反向验证
你可以尝试用不可寻址的临时type2值调用该方法,就会触发编译错误,符合方法集规则的判断:
type2{}.type1Meth2() // 编译报错:cannot call pointer method on type2{} literal, cannot take address of type2{} literal
内容的提问来源于stack exchange,提问作者Ankur Agarwal
相关产品推荐
相关产品推荐

