[譯]在Go中使用'self'作為receiver變量是一種好的實(shí)踐嗎?

原帖:stackoverflow

原問(wèn)題

我回憶了一下,沒(méi)有任何博客或者視頻的作者在Go中以selfthis作為方法的receiver,但是在stack overflow的很多問(wèn)題下面就經(jīng)常能看見(jiàn)有人以selfthis作為方法的receiver。這讓我感到疑惑,用self作為receiver名有什么問(wèn)題嗎?

好像曾經(jīng)在哪里看到過(guò)有人說(shuō)receiver并不完全是一個(gè)指向自身的指針,誰(shuí)能解釋一下這種說(shuō)法嗎。把self看做指向自身的指針有什么問(wèn)題嗎?

例子:

type MyStruct struct {
  Name string
}

那種方式比較合適呢,還是兩種都o(jì)k?

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

or

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

回答

其他的人都說(shuō)的很好了,我再補(bǔ)充幾點(diǎn)重要的:

以普通函數(shù)的方式調(diào)用Method Set里的方法

在Go里,不但可以通過(guò)receiver的方式調(diào)用一個(gè)方法,還可以像一個(gè)普通的函數(shù)一樣調(diào)用。在type的名稱后跟上相應(yīng)方法的名稱并將receiver作為第一個(gè)參數(shù)傳入(這種使用方式叫做使用method expression)。

demo:

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)
}

運(yùn)行結(jié)果:

My receiver is 46
My receiver is 51

可以看出來(lái),你手動(dòng)調(diào)用并賦予了執(zhí)行的上下文環(huán)境,使得self失去了他的語(yǔ)義,與面向?qū)ο缶幊讨袕V泛引用的一句話“調(diào)用一個(gè)對(duì)象的方法就是給這個(gè)對(duì)象傳遞信息”的概念沒(méi)有一點(diǎn)聯(lián)系。

總的來(lái)說(shuō),在Go里方法其實(shí)就是將函數(shù)語(yǔ)義化地綁定在指定type上,并接受一個(gè)叫做receiver的參數(shù),不管你以哪種方式調(diào)用方法,調(diào)用過(guò)程其實(shí)都是一樣的。與大多數(shù)主流語(yǔ)言不同,Go并沒(méi)有將方法調(diào)用的細(xì)節(jié)隱藏起來(lái)。

receiver并不一定能在方法內(nèi)部被改變

在上面的demo中可以看到我定義了一個(gè)Bar()方法,他的receiver并不是一個(gè)指針類型,如果試著在方法內(nèi)部為receiver賦值就會(huì)發(fā)現(xiàn)賦值是可以賦值,但是并不會(huì)影響到方法的調(diào)用者,因?yàn)閞eceiver的值(Go中所有的值都一樣)是按值傳遞的(所以這里的receiver只是調(diào)用者的一份拷貝)。

為了能在方法里改變r(jià)eceiver能影響到方法調(diào)用者,你需要定義一個(gè)指針類型的receiver:

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

例子中的方法接收了一個(gè)確定類型的值,可以看出使用self表示“自身”已經(jīng)毫無(wú)意義了。這與傳統(tǒng)面向?qū)ο笳Z(yǔ)言默認(rèn)將對(duì)象按引用傳遞不同,在Go里你可以在任何東西“里”定義方法(包括在方法上定義方法,net/http標(biāo)準(zhǔn)庫(kù)就是這么做的),“對(duì)象里的方法”這種概念已經(jīng)不復(fù)存在了。

同樣的值在不同時(shí)候可以有不同的方法

在Go里,方法可以非常方便用與組織特定類型的各種功能。在代碼執(zhí)行期間,同樣的值可以擁有有不一樣的方法,結(jié)合Go提供的接口,鴨子類型的編碼風(fēng)格,使得這種(動(dòng)態(tài)織入方法)編碼方式非常流行。我們經(jīng)常能看到編碼時(shí)會(huì)定義一個(gè)“Support”類型,在其中放很多為其他不同類型提供的方法。

標(biāo)準(zhǔn)庫(kù)sort就是一個(gè)很好的例子:在sort包里提供一種IntSlice類型,這種類型允許你對(duì)整數(shù)類型的slice([]int)進(jìn)行排序。只要將slice轉(zhuǎn)換為IntSlice之后就擁有了各種對(duì)slice進(jìn)行排序的方法,并且排序時(shí)原來(lái)的slice值并不會(huì)被改變(因?yàn)?code>IntSlice就是type IntSlice []int)。很難去說(shuō)IntSlice里的所有方法的receive帶有self這層含義,因?yàn)檫@里所有的方法都是提供給其他類型使用的。從哲♂學(xué)的角度上看,這些工具類型并不存在“self”的概念。

總結(jié)

所以,應(yīng)該讓思維保持簡(jiǎn)單,不要給自己的想法加上太多的枷鎖,并不一定要使用語(yǔ)義化的方式去解釋Go所提供的清晰明了的編碼哲學(xué)。我自己對(duì)Go語(yǔ)言的學(xué)習(xí)理解來(lái)看,Go語(yǔ)言首要的編碼風(fēng)格應(yīng)該是實(shí)用(與務(wù)虛相反)。所以每當(dāng)你“感覺(jué)”某些概念很不自然,你就可以試著去弄清楚為什么這些東西在Go里要這樣設(shè)計(jì),大多數(shù)情況你最后會(huì)發(fā)現(xiàn)這種設(shè)計(jì)真是精妙。(我必須承認(rèn)熟悉C語(yǔ)言對(duì)于理解Go語(yǔ)言里methods設(shè)計(jì)有很大的幫助,更有助于理解這個(gè)問(wèn)題。)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,030評(píng)論 0 9
  • 出處---Go編程語(yǔ)言 歡迎來(lái)到 Go 編程語(yǔ)言指南。本指南涵蓋了該語(yǔ)言的大部分重要特性 Go 語(yǔ)言的交互式簡(jiǎn)介,...
    Tuberose閱讀 18,717評(píng)論 1 46
  • 第5章 引用類型(返回首頁(yè)) 本章內(nèi)容 使用對(duì)象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,665評(píng)論 0 4
  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,872評(píng)論 33 466
  • 本文為 Spark 2.0 源碼分析筆記,某些實(shí)現(xiàn)可能與其他版本有所出入 再次重申標(biāo)題中的 Master 是指 S...
    牛肉圓粉不加蔥閱讀 1,470評(píng)論 0 1

友情鏈接更多精彩內(nèi)容