除了其他人所说的(特别是
PeterSO和
dskinner-在他对彼得的回答的评论中)之外,还请注意几件重要的事情:
您可以调用类似简单函数的方法
在Go中,您可以调用 任何 方法函数,而不是将其作为接收器上的方法,而可以将其作为常规函数-只需通过将其名称限定为定义为方法的类型的名称,然后将其
显式
传递给接收器参数即可(获取使用方法表达式()调用方法中的简单函数。
展示:
package mainimport "fmt"type Foo intfunc (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 46My 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会很有帮助。)



