go - Go 中基类型方法指针的选择器

标签 go language-lawyer specifications

很明显,下面的代码可以正常工作:

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 的方法集。我是否理解带注释的行的规范错误或正确性是基于其他规范规则?

最佳答案

你引用了:

x.f denotes the field or method at the shallowest depth in T

引用是指深度"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.

关键是嵌入。您的结构不嵌入单一类型。因此,根据定义,您的TM深度是

您的 t 变量的类型为 *T(即 &T{} 表达式的类型,即 taking the address of结构 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 是对非接口(interface)方法 T.M 的引用,由于 t 是指针,因此会自动取消引用:(*t).M().

现在让我们看一个例子,其中“最浅深度”确实很重要。

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.MT2.M。但由于 T2.T.M 的深度为 ,而 T2.M 的深度为 ,因此 T2 .M 位于 T2 中最浅的深度,因此 t2.M 将表示 T2.M 而不是 T2 .T.M,所以上面的示例打印(在 Go Playground 上尝试):

T2.M()

关于go - Go 中基类型方法指针的选择器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57747668/

相关文章:

c++ - 纯虚函数会阻止隐式生成的 move 构造函数吗?

css - css 'ex' 单元的值是多少?

javascript - Date.prototype.toLocaleTimeString() 中的 hourCycle 选项有什么区别

string - 为什么 string.Replace 在 golang 中不起作用

sockets - 第一次响应后 TCP 服务器失败

arrays - 如何在循环中使用golang的追加到数组中

c++ - C++20 是否强制将源代码存储在文件中?

c++ - 分配过大的堆栈结构是未定义的行为吗?

regex - 如何在 RPM 规范文件中使用正则表达式?

Golang gorename 工具失败