首页 > 文章列表 > 在 Go 中,将接收者变量命名为“自我”是误导性的还是好的做法?

在 Go 中,将接收者变量命名为“自我”是误导性的还是好的做法?

golang
378 2023-03-08

问题内容

我在 Go 上看过相当多的博客和视频,据我记得,没有一个作者在编写方法时使用“self”或“this”作为接收器变量。然而,似乎有很多关于堆栈溢出的问题可以做到这一点,这让我思考这是否会误导将变量命名为“self”?

阅读方法集的规范并不能提供任何证据(在我的解释中)。

我似乎记得在某个地方发现它并不是真正的自我指针,任何人都可以列出证据或提供任何一种方式的推理,如果将其视为“自我”可能会出现任何问题/陷阱?

一个简单的例子:

type MyStruct struct {
    Name string
} 

哪种方法更合适,或两者兼而有之?

func (m *MyStruct) MyMethod() error {
    // do something useful
}

要么

func (self *MyStruct) MyMethod() error {
    // do something useful
}

正确答案

除了其他人所说的(尤其是他PeterSOdskinner彼得答案的评论),请注意几件重要的事情:

你可以像一个简单的函数一样调用一个方法

在 Go 中,您可以调用 任何 方法函数,而不是作为接收器上的方法,而是作为常规函数——这意味着通过使用它定义为方法的类型的名称来限定其名称并 显式 传递一个接收器参数 (使用方法表达式调用从方法中获取简单函数)。

展示:

package main

import "fmt"

type Foo int

func (f Foo) Bar() {
    fmt.Printf("My receiver is %vn", f)
}

func main() {
    a := Foo(46)
    a.Bar()
    b := Foo(51)
    Foo.Bar(b)
}

游乐场链接。

运行时,该程序打印:

My receiver is 46
My receiver is 51

正如你所看到的,self这里失去了它的神圣意义,因为你刚刚调用了一个 人为 地为其构造上下文的方法,这与被引用的“调用对象的方法是将消息传递给该对象”概念无关。

回顾一下,在 Go 中,方法只是一个在语义上绑定到特定类型的函数,它接收一个额外的参数——即接收者——不管它是如何调用的。与许多其他主流语言相反,Go 并没有隐藏这个事实。

接收器在其类型上定义的方法内不一定是 可变的

如我的示例所示,我在Bar()非指针接收器上定义了一个方法,如果您尝试为接收器分配一个值,该值将成功但不会影响调用方,因为接收Go 中的所有内容都是按值传递的(因此该整数刚刚被复制)。

为了能够在方法中改变接收者的值,你必须在一个适当类型的指针上定义它,比如

func (f *Foo) Bar() {
    // here you can mutate the value via *f, like
    *f = 73
}

同样,您可以看到使用self“我”、“我的内部”的含义在这里变得没有意义:在我的示例中,该方法仅接收它知道的类型的值。您可以看到这与许多 OO 语言形成对比,在这些语言中,对象是通常通过引用传递的黑盒子。在 Go 中,您几乎可以在任何东西(包括标准包使用的其他方法)上定义一个方法,这会net/http削弱“方法用于对象”的概念。

不同的方法集可能在不同的时间适用于相同的值

在 Go 中,方法是围绕特定类型对功能进行分组的便捷方式,不同的方法集可能适用于程序流不同点的相同值。结合他们提供的接口和鸭式打字,这个概念真的很繁荣。这个想法是,在 Go 中,有一个定义“支持”类型的习惯用法,这些类型对其他类型的值执行某些操作。

一个很好的例子是标准包sort:例如,它提供了IntSlice允许您对整数切片(type 的值)进行排序的类型[]int。为此,您将切片类型转换为sort.IntSlice,并且您获得的值具有一整套用于对切片进行排序的方法,而 您的值的内部表示没有改变 ——因为sort.IntSlice定义type IntSlice []int. 在该IntSlice类型的每个方法中,很难将其接收者值的含义与self“暗示”相协调,因为该类型的存在只是为了为另一种类型提供一组方法;在哲学意义上,此类实用程序类型没有“自我”的概念;-)

结论

所以我想说,让事情保持简单,不要试图用没有 明确 说明它提供的语义来“重载” Go 采用的清晰简单的方法。

再来一注。我对 Go 习语的个人看法是,Go 的最重要属性是它的实用性(与理想主义等相反),所以如果你看到一些“感觉”不自然的概念,试着弄清楚 为什么 它是这样设计的,而且大多数通常,您会发现为什么这个概念会在您的大脑中“点击”并变得自然。(我必须承认,要通过理解 Go 中的方法来解决这个特殊问题,对工作熟悉C会有很大帮助。)