在Go中将接收者变量命名为“自我”误导或良好习惯? [英] In Go is naming the receiver variable 'self' misleading or good practice?

查看:152
本文介绍了在Go中将接收者变量命名为“自我”误导或良好习惯?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我见过相当多的博客和博客, Go上的视频以及据我所知,在编写方法时,没有一个作者使用'self'或'this'作为接收者变量。然而,堆栈溢出似乎有很多问题是这样做的,它让我想到如果这是误导命名变量self?

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

我似乎记得在某个地方发现它不是真正的自我指针,任何人都可以列出证据或提供推理无论是哪种方式,以及是否有任何问题/陷阱可能因为它被认为是自我而出现?



一个简单的例子:

 类型MyStruct结构{
名称字符串
}

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

  func(m * MyStruct)MyMethod()错误{
//做一些有用的事情
}



$ p $ func(self * MyStruct)MyMethod()错误{
//做一些有用的事
}


解决方案

除了其他人说的话外(尤其是 PeterSO ds kinner —在他对彼得的回答的评论中),请注意几件重要的事情:

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

在Go中,您可以将任何方法函数作为接收方的方法而不是作为常规函数调用,只需将其名称用将其定义为方法的类型名称​​显式将它传递给接收器参数(从一个方法中获取一个简单函数称为
,使用方法表达式)。



演示:

 包主
$ b导入fmt

类型Foo int

func (f Foo)Bar(){
fmt.Printf(我的接收器是%v \ n,f)
}

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



运行时,此程序会显示:

 我的收件人是46 
我的收件人是51

正如你所看到的, self 在这里失去了神圣的含义,因为你刚刚调用了一个方法 构造它的上下文,没有任何关系,被称为调用对象的方法是将消息传递给该对象的概念。



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



接收器不一定是可变的它的类型



正如我的例子所示,我定义了一个方法, Bar() - 指针接收器,如果您尝试为接收器分配一个值,但这个值将会成功,但不会影响调用者,因为接收器(如Go中的所有东西)已按值传递(以便刚刚复制整数) 。

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

  func(f * Foo)Bar(){
//这里您可以通过* f修改数值,如
* f = 73
}

再次,您可以看到使用 self 意思是我,我的内部在这里变得毫无意义:在我的例子中,该方法仅仅收到一个值OWS。你可以看到这与许多OO语言形成鲜明对比,在OO语言中,一个对象通常是通过引用传递给对象的黑盒子。在Go中,您可以定义几乎任何方法(包括其他方法),方法 net / http 标准包,顺便说一下)这会削弱方法用于对象的概念。

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



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



一个很好的例子是<标准软件包 sort> :例如,它提供了键入 IntSlice ,它允许您对整数片段进行排序—类型为 [] int 的值。要做到这一点,你可以将你的切片类型转换为 sort.IntSlice ,结果得到的值有一整套用于排序切片的方法,而内部您价值的表现没有改变—因为 sort.IntSlice 定义为键入IntSlice [] int 。在 IntSlice 类型的每种方法中,很难将接收者值的含义与 self &mdash协调一致,该类型仅用于为另一类型提供一组方法;在哲学意义上,这种效用类型没有自我的概念; - )

结论



我想说的是,让事情变得简单,并且不要试图通过Go所采用的清晰而简单的方法来超载它所提供的 状态。



还有一点需要注意。我个人对Go的习语的理解是,Go的最重要属性是它的实用性(与理想主义等相对),所以如果你看到一些感觉非自然的概念,试图解决它的原因 它是按照这种方式设计的,而且大多数情况下你会发现为什么这样的概念会在你的大脑中点击并且变得自然。 (我必须承认,为了在Go中理解这个特定的问题,熟悉 C 会有很大的帮助。)


I have seen a fair amount of blogs & videos on Go and as far as I recall, none of the authors use 'self' or 'this' for the receiver variable when writing methods. However there seems to be a number of questions on stack overflow that do this, and it got me thinking about if this is misleading to name the variable 'self'?

Reading the Spec for Method Sets does not provide any evidence either way (in my interpretation).

I seem to recall finding somewhere that it was not really a self pointer, can anyone list evidence or provide reasoning either way, and if any problems/traps that might occur from thinking of it as 'self'?

A quick example:

type MyStruct struct {
    Name string
} 

Which method is more appropriate, or both?

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

or

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

解决方案

In addition to what others said (especially PeterSO and dskinner—in his comment to the Peter's answer), note several important things:

You can call a method like a simple function

In Go, you can call any method function not as a method on a receiver but rather as a regular function—simply by qualifying its name with the name of the type it's defined to be a method on and explicitly passing it a receiver argument (obtaininig a simple function from a method is called using a method expression).

To demonstrate:

package main

import "fmt"

type Foo int

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

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

(Playground link.)

When run, this program prints:

My receiver is 46
My receiver is 51

As you can see, self loses its sacred meaning here because you've just called a method artifically constructing the context for it which has nothing to do with the much cited "calling an object's method is passing a message to that object" concept.

To recap, in Go, a method is just a function semantically bound to a particular type which receives a single extra argument—its receiver—no matter how it's called. Contrary to many other mainstream languages, Go does not hide this fact under the carpet.

A receiver is not necessarily mutable inside a method defined on its type

As demonstrated in my example, I've defined a method, Bar(), on a non-pointer receiver, and if you'll try to assign a value to the receiver that will succeed but won't affect the caller because the receiver—as everything in Go—has been passed by value (so that integer has just been copied).

To be able to mutate the receiver's value in the method, you'd have to define it on an appropriately-typed pointer, like

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

Again, you can see that using self meaning "me", "my internals" becomes moot here: in my example the method merely received a value which type it knows. You can see this is in contrast with many OO-languages in which an object is a black box usually passed around by reference. In Go, you can define a method on virtually anything (including other methods, which is used by the net/http standard package, by the way) which erodes that "methods are for objects" concept.

Different sets of methods might be applicable to the same value at different times

In Go, methods are a convenient way to group functionality around particular types, and different sets of methods might be applicable to the same value in different points of the program flow. Combined with interfaces and duck-typing they provide, this concept really flourishes. The idea is that in Go, there's an idiom of defining "support" types which perform certain operation on values of some other type.

A good example of this is the standard package sort: for instance, it provides the type IntSlice which allows you to sort a slice of integers—a value of type []int. To do that you type-convert your slice to sort.IntSlice and the value you get as a result has a whole set of methods for sorting your slice while the internal representation of your value has not changed— because sort.IntSlice is defined as type IntSlice []int. In each method of that IntSlice type, it's hard to reconcile the meaning of their receiver value with self—simply because the type solely exists to provide a set of methods for another type; in a philosophical sense, such utility types have no concept of "self" ;-)

Conclusion

So I'd say, keep things simple in your head and do not try to "overload" the clear and simple approach taken by Go with semantics it does not explicitly state it provides.

One more note. My personal perception of Go's idioms as I learned them is that the paramount property of Go is its practicality (as opposed to idealism etc) so if you see some concept which "feels" unnatural try to work out why it's designed that way, and most often you'll discover why so the concept "clicks" in your brain and gets natural. (I must admit that to grok this particular problem with understanding methods in Go, a good working familiarity with C would be of much help.)

这篇关于在Go中将接收者变量命名为“自我”误导或良好习惯?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆