这个问题的标题几乎是从golang规范中引用的:
给定结构类型S和名为T的类型,提升的方法包含在结构的方法集中,如下所示:
如果S包含匿名字段T,则S和*S的方法集都包括具有接收方T的提升方法.*S的方法集还包括具有接收方*T的提升方法.
这是一个go操场,显示该方法inc()
被提升.
package main import ( "fmt" ) // just an int wrapper type integer struct { i int } func (self *integer) inc() { self.i++ } type counter struct { integer } func main() { c := counter{} c.inc() fmt.Println(c) }
Stephen Wein.. 7
没有*T的方法不会被提升.规范没有明确允许它,因此不允许.但是,这背后有一个原因.
有时您可以在T上调用*T方法.但是,有一个隐式引用.*T的方法不被视为T方法集的一部分.
从Go规范的调用部分:
如果x是可寻址的并且&x的方法集包含m,则xm()是(&x).m()的简写
从Go规范的地址运算符部分:
对于类型为T的操作数x,地址操作&x生成类型为*T到x的指针.操作数必须是可寻址的,即,变量,指针间接或切片索引操作; 或可寻址结构操作数的字段选择器; 或者可寻址数组的数组索引操作.作为可寻址性要求的例外,x也可以是(可能带括号的)复合文字.
如果S包含*T,您甚至不需要获取其地址,因此可以调用方法.如果*S包含T,则知道T是可寻址的,因为T是指向间接结构的字段选择器.对于包含T的S,这不能保证.
更新:为什么该代码有效?
请记住,*S包含*T的方法集.另外,正如我之前引用的那样:
如果x是可寻址的并且&x的方法集包含m,则xm()是(&x).m()的简写
将两者放在一起,你就得到了答案.计数器是可寻址的,&计数器包含*T的方法集.因此,counter.Inc()是(&counter).Inc()的简写.
没有*T的方法不会被提升.规范没有明确允许它,因此不允许.但是,这背后有一个原因.
有时您可以在T上调用*T方法.但是,有一个隐式引用.*T的方法不被视为T方法集的一部分.
从Go规范的调用部分:
如果x是可寻址的并且&x的方法集包含m,则xm()是(&x).m()的简写
从Go规范的地址运算符部分:
对于类型为T的操作数x,地址操作&x生成类型为*T到x的指针.操作数必须是可寻址的,即,变量,指针间接或切片索引操作; 或可寻址结构操作数的字段选择器; 或者可寻址数组的数组索引操作.作为可寻址性要求的例外,x也可以是(可能带括号的)复合文字.
如果S包含*T,您甚至不需要获取其地址,因此可以调用方法.如果*S包含T,则知道T是可寻址的,因为T是指向间接结构的字段选择器.对于包含T的S,这不能保证.
更新:为什么该代码有效?
请记住,*S包含*T的方法集.另外,正如我之前引用的那样:
如果x是可寻址的并且&x的方法集包含m,则xm()是(&x).m()的简写
将两者放在一起,你就得到了答案.计数器是可寻址的,&计数器包含*T的方法集.因此,counter.Inc()是(&counter).Inc()的简写.