为什么在比较之后将选择器转换为指针是非法的?

huangapple go评论98阅读模式
英文:

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

huangapple
  • 本文由 发表于 2016年11月25日 19:10:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/40803654.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定