go中基类型方法的指针选择器
Selector of pointer for method from base type in go
很明显,以下代码可以正常工作:
package main
import "fmt"
type T struct {
a int
}
func (t T) M() {
fmt.Println("M method")
}
func main() {
var t = &T{1}
t.M() // it's interesting
}
但是从specification可以看出:
For a value x of type T or *T where T is not a pointer or interface type, x.f denotes the field or method at the shallowest depth in T where there is such an f. If there is not exactly one f with shallowest depth, the selector expression is illegal.
但在示例中 M
不是来自 *T
,而是来自 T
。我知道 *T
包含 T
的方法集,但正如我所见,规范并未告诉我们有关 *T
的方法集。我是否理解规范错误或注释行的正确性是基于其他规范规则?
来自Method Sets:
The method set of the corresponding pointer type *T is the set of all methods declared with receiver *T or T (that is, it also contains the method set of T).
你引用了:
x.f
denotes the field or method at the shallowest depth in T
引用的是depth。 "Definition" of depth is:
A selector f
may denote a field or method f
of a type T
, or it may refer to a field or method f
of a nested embedded field of T
. The number of embedded fields traversed to reach f
is called its depth in T
. The depth of a field or method f
declared in T
is zero. The depth of a field or method f
declared in an embedded field A
in T
is the depth of f
in A
plus one.
关键是嵌入。您的结构没有嵌入单一类型。所以根据定义,你的 T.M
的深度是 zero.
你的t
变量是*T
类型(即&T{}
表达式的类型,即taking the address of a struct composite literal:它生成一个指向唯一变量的指针用文字的值初始化)。
并引用自 Spec: Method values:
As with selectors, a reference to a non-interface method with a value receiver using a pointer will automatically dereference that pointer: pt.Mv
is equivalent to (*pt).Mv
.
t.M
是对非接口方法T.M
的引用,由于t
是指针,所以会自动解引用:(*t).M()
.
现在让我们看一个例子,其中 "at the shallowest depth" 确实很重要。
type T struct{}
func (t T) M() { fmt.Println("T.M()") }
type T2 struct {
T // Embed T
}
func (t T2) M() { fmt.Println("T2.M()") }
func main() {
var t T = T{}
var t2 T2 = T2{T: t}
t2.M()
}
在main()
中我们调用t2.M()
。由于 T2
嵌入了 T
,因此可以引用 T2.T.M
和 T2.M
。但是由于 T2.T.M
的深度是 one 而 T2.M
的深度是 zero,所以 T2.M
在T2
中的最浅深度,因此 t2.M
将表示 T2.M
而不是 T2.T.M
,因此上面的示例打印(在 Go Playground 上尝试):
T2.M()
很明显,以下代码可以正常工作:
package main
import "fmt"
type T struct {
a int
}
func (t T) M() {
fmt.Println("M method")
}
func main() {
var t = &T{1}
t.M() // it's interesting
}
但是从specification可以看出:
For a value x of type T or *T where T is not a pointer or interface type, x.f denotes the field or method at the shallowest depth in T where there is such an f. If there is not exactly one f with shallowest depth, the selector expression is illegal.
但在示例中 M
不是来自 *T
,而是来自 T
。我知道 *T
包含 T
的方法集,但正如我所见,规范并未告诉我们有关 *T
的方法集。我是否理解规范错误或注释行的正确性是基于其他规范规则?
来自Method Sets:
The method set of the corresponding pointer type *T is the set of all methods declared with receiver *T or T (that is, it also contains the method set of T).
你引用了:
x.f
denotes the field or method at the shallowest depth inT
引用的是depth。 "Definition" of depth is:
A selector
f
may denote a field or methodf
of a typeT
, or it may refer to a field or methodf
of a nested embedded field ofT
. The number of embedded fields traversed to reachf
is called its depth inT
. The depth of a field or methodf
declared inT
is zero. The depth of a field or methodf
declared in an embedded fieldA
inT
is the depth off
inA
plus one.
关键是嵌入。您的结构没有嵌入单一类型。所以根据定义,你的 T.M
的深度是 zero.
你的t
变量是*T
类型(即&T{}
表达式的类型,即taking the address of a struct composite literal:它生成一个指向唯一变量的指针用文字的值初始化)。
并引用自 Spec: Method values:
As with selectors, a reference to a non-interface method with a value receiver using a pointer will automatically dereference that pointer:
pt.Mv
is equivalent to(*pt).Mv
.
t.M
是对非接口方法T.M
的引用,由于t
是指针,所以会自动解引用:(*t).M()
.
现在让我们看一个例子,其中 "at the shallowest depth" 确实很重要。
type T struct{}
func (t T) M() { fmt.Println("T.M()") }
type T2 struct {
T // Embed T
}
func (t T2) M() { fmt.Println("T2.M()") }
func main() {
var t T = T{}
var t2 T2 = T2{T: t}
t2.M()
}
在main()
中我们调用t2.M()
。由于 T2
嵌入了 T
,因此可以引用 T2.T.M
和 T2.M
。但是由于 T2.T.M
的深度是 one 而 T2.M
的深度是 zero,所以 T2.M
在T2
中的最浅深度,因此 t2.M
将表示 T2.M
而不是 T2.T.M
,因此上面的示例打印(在 Go Playground 上尝试):
T2.M()