英文:
Golang: Why selector to pointers is illegal after comparison?
问题
我正在阅读有关选择器的规范:https://golang.org/ref/spec#Selectors
为什么 q.M0() 是无效的,而 p.M0() 是有效的,且 q=p。对我来说非常奇怪。
相关的源代码:
type T0 struct {
	x int
}
func (*T0) M0()
type T1 struct {
	y int
}
func (T1) M1()
type T2 struct {
	z int
	T1
	*T0
}
func (*T2) M2()
type Q *T2
var t T2     // with t.T0 != nil
var p *T2    // with p != nil and (*p).T0 != nil
var q Q = p
p.M0()       // ((*p).T0).M0()      M0 expects *T0 receiver
q.M0()       // (*q).M0 is valid but not a field selector
英文:
I'm reading the spec about selectors: https://golang.org/ref/spec#Selectors
Why q.M0() is invalid. While p.M0() is valid and q=p. Very strange for me.
The relevant source code:
type T0 struct {
	x int
}
func (*T0) M0()
type T1 struct {
	y int
}
func (T1) M1()
type T2 struct {
	z int
	T1
	*T0
}
func (*T2) M2()
type Q *T2
var t T2     // with t.T0 != nil
var p *T2    // with p != nil and (*p).T0 != nil
var q Q = p
p.M0()       // ((*p).T0).M0()      M0 expects *T0 receiver
q.M0()       // (*q).M0 is valid but not a field selector
答案1
得分: 7
为什么 q.M0() 是无效的,而 p.M0() 是有效的,且 q=p?对我来说非常奇怪。
q 被初始化为 var q Q = p,但这并不意味着它们相等。这个赋值操作是有效的,因为它没有违反可赋值性规则,但是 q 的类型与 p 的类型不同。
q 的类型是 Q(其中 type Q *T2),而 p 的类型是 *T2。
在 Go 语言中,方法属于特定的类型。当你这样做时:
type Q *T2
它创建了一个名为 Q 的新类型(*T2 是其底层类型)。这个新类型没有任何方法,它不会从 *T2 中“继承”任何方法,因此 q.M0() 将在编译时出错:
> q.M0 undefined (type Q has no field or method M0)
注意:
你可能仍然觉得奇怪,因为 M0() 的声明如下:
func (*T0) M0()
它具有 *T0 的接收器,因此它属于类型 *T0,然而 p 的类型是 *T2,所以 *T2 不应该有这个 M0() 方法,因此 p.M0() 也应该是无效的。但是 T2 是一个结构体,它嵌入了 *T0,所以 *T0 的方法被_提升_了,并且它们将在 T2 的方法集中。
还可以参考这个相关的问题:https://stackoverflow.com/questions/40803654/golang-why-selector-to-pointers-is-illegal-after-comparison/40804236#40804236
英文:
> Why q.M0() is invalid. While p.M0() is valid and q=p. Very strange for me.
q is initialized like var q Q = p, but it does not mean they are equal. The assignment is valid because it does not violate the assignability rules, but type of q is different than type of p.
Type of q is Q (where type Q *T2), and type of p is *T2.
In Go, methods belong to a specific type. When you do this:
type Q *T2
It creates a new type named Q (*T2 being its underlying type). The new type will have 0 methods, it does not "inherit" any methods from *T2, hence q.M0() will be a compile-time error:
> q.M0 undefined (type Q has no field or method M0)
Note:
You may still think it's strange because M0() is declared like this:
func (*T0) M0()
It has *T0 receiver so it belongs to the type *T0, yet type of p is *T2, so *T2 should not have this M0() method and therefore p.M0() should also be invalid. But T2 is a struct which embeds *T0, and so methods of *T0 are promoted, and they will be in the method set of T2.
Also see this related question: https://stackoverflow.com/questions/40803654/golang-why-selector-to-pointers-is-illegal-after-comparison/40804236#40804236
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。



评论