当前位置: 首页 > 面试题库 >

在Go中,将接收方变量命名为“自我”具有误导性或良好做法吗?

万修然
2023-03-14
问题内容

我在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 %v\n", 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语言形成对比,在OO语言中,对象是黑匣子,通常通过引用传递。在Go中,您几乎可以在任何方法(包括net/http标准方法使用的其他方法)上定义方法,从而侵蚀“方法是针对对象的”概念。

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

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

标准包sort就是一个很好的例子:例如,它提供了IntSlice允许您对整数切片(type的值)进行排序的类型[]int。要做到这一点,你的片型转换为sort.IntSlice和你得到的结果值有一整套的同时,为您的排序方法切片
你的价值的内部表示并没有改变 -因为sort.IntSlice被定义为type IntSlice []int。在该IntSlice类型的每种方法中,很难将接收者值的含义与—
self仅因为该类型存在以为另一种类型提供一组方法;从哲学的意义上说,这种效用类型没有“自我”的概念;-)

结论

因此,我想说的是,保持头脑简单,不要试图“超载” Go所采用的清晰,简单的方法,而语义并未 明确 说明它提供的方法。

还有一点。我对Go的成语的个人看法是,Go的最重要的特性是它的实用性(与理想主义等相对),因此,如果您看到某种“感觉”不自然的概念,试图弄清楚 为什么
它是这样设计的,并且大多数通常,您会发现为什么这个概念在您的大脑中“点击”并变得自然。(我必须承认,通过理解Go中的方法来解决这个特定问题,对工作有很好的了解C会很有帮助。)



 类似资料:
  • 问题内容: 我已经为JDBC连接编写了一个简单的包装程序,它可以工作,但是我想通过最佳实践来对其进行改进。它基本上有类似的方法,,,,,,和。为简单起见,我仅在此处发布前4种方法。 笔记: 可以重复使用同一查询对象,例如打开和关闭它,以及在再次打开之后。 我不是关闭每个查询的连接,而是关闭准备好的语句(这是正确的,或者我可以让准备好的语句保持打开状态,因为Connection对象会关闭它吗?) 当

  • 问题内容: 我一直看到警告,不要在JavaScript中使用全局变量,但是似乎人们说这的唯一原因是因为阻塞了全局名称空间。我可以想象通过将所有变量放入一个大对象中来轻松解决此问题。现在的问题是:除了方便起见,还有其他原因不使用全局变量吗?它们是否涉及任何性能或兼容性问题? 问题答案: 它们使全局名称空间混乱,并且查找速度比局部变量慢。 首先,拥有许多全局变量始终是一件坏事,因为很容易忘记您在某个地

  • 问题内容: 我目前遇到一个问题,我有两个我需要调用的模块,它们需要能够修改相同的变量。 我决定创建一个名为的全局变量,并在其中存储所需的变量。 但是我一直在阅读,使用全局变量是一种不好的做法。为什么? 我仅创建一个变量,该变量不应与其他任何冲突,因为它是我的应用程序的名称。 问题答案: 几乎在所有编程语言中,全局变量都被视为反模式,因为它们使遵循和调试代码变得非常困难。 浏览代码时,您永远不知道哪

  • 问题内容: 在某些地方,我看到了语法,其中用名称初始化变量,有时不使用名称初始化。例如: 命名变量有 什么意义? 问题答案: 该参数是可选的(可以创建带有或不带有它的变量和常量),并且在程序中使用的变量不依赖于它。名称在两个地方可能会有所帮助: 当您想要保存或还原变量时 (可以在计算后将它们保存到二进制文件中)。从文档: 默认情况下,它为每个变量使用Variable.name属性的值 但是你有变量

  • 以上程序是否有效C++17?如果没有,为什么?如果是,是不是编译器bug导致它无法运行?

  • 问题内容: 过去,我使用以下方法读取大量代码: 这样做是惯例吗? 优点和缺点是什么? 在我看来,这就像完成异常的“ Agent Orange”方式 编辑 处理方法中的预期异常 引发意外异常(一对一) 不在乎错误 那是路要走吗? 问题答案: 你不应该扔。这就是为什么。 Throwable是可抛出的事物层次结构的顶部,由and组成。由于根据定义是由不可挽救的条件引起的,因此将它们包括在方法声明中是没有