2013-08-26 17 views
10

好像你總是希望這樣的:接收器爲什麼在Go中通過價值?

func (self *Widget) Do() { 
} 

,而不是這個

func (self Widget) Do() { 
} 

如果是這樣,那麼方式使用後者的語法來獲取以前的語義應該是。即接收者應該通過參考。

回答

24

這是因爲everything in Go is pass by value。這使得它與其他C族語言一致,並且意味着你永遠不需要記住你所看到的情況是否通過了價值。

從該鏈接:

如在C系列中的所有語言,一切都在走的是按值傳遞。也就是說,一個函數總是獲取被傳遞的東西的副本,就好像有一個賦值語句賦值給參數一樣。例如,將int值傳遞給函數會生成int的副本,並且傳遞指針值會創建指針的副本,但不會指向它指向的數據。 (見下一節的這如何影響方法的接收器的討論。)

再後來:

func (s *MyStruct) pointerMethod() { } // method on pointer 
    func (s MyStruct) valueMethod() { } // method on value 

對於程序員不習慣指針,這兩個例子之間的區別可以是混亂,但情況其實很簡單。當在一個類型上定義一個方法時,接收者(在上面的例子中爲s)的行爲就像它是該方法的參數一樣。無論是將接收器定義爲值還是指針都是同一個問題,那麼函數參數應該是值還是指針。有幾個考慮因素。

首先,最重要的是,該方法是否需要修改接收器?如果是這樣,接收器必須是一個指針。 (切片和貼圖作爲參考,所以它們的故事更加微妙,但是例如改變方法中切片的長度,接收器必須仍然是一個指針。)在上面的例子中,如果pointerMethod修改了字段s,調用者將看到這些更改,但valueMethod是使用調用者參數的副本(這是傳遞值的定義)調用的,因此調用者不會看到它的更改。順便說一下,指針接收器與Java中的情況相同,儘管在Java中指針隱藏在封面之下;這是Go的價值接受者是不尋常的。

二是對效率的考慮。如果接收器很大,例如一個大結構,使用指針接收器會便宜得多。

接下來是一致性。如果某些類型的方法必須具有指針接收器,則其餘的方法也應該如此,因此無論類型如何使用,方法集都是一致的。有關詳細信息,請參閱方法集部分。

對於基本類型,切片和小結構等類型,值接收器非常便宜,因此除非方法的語義需要指針,否則值接收器是高效且清晰的。

+1

優秀的答案! :-) –

+0

第二句引言中的所有內容都表明,在一個好的設計中,幾乎每個接收器都應該是一個指針。它提到的唯一情況是你可能會考慮使用非指針,當值很小時。以犧牲良好設計爲代價推廣小型案例似乎不是一個好選擇。 – allyourcode

+0

s/choice/trade/ – allyourcode

6

有時候你不要想通過參考,雖然。

func (self Widget) Get() Value { 
} 

的語義如果你有一個小的不可變對象,這會很有用。調用者可以確切地知道這種方法不會修改它的接收者。他們不能知道這是否接收器是一個指針,而不先讀取代碼。

只是通過看這個方法我可以知道GetConfig總是會返回相同的配置上擴大例如

// accessor for things Config 
func (self Thing) GetConfig() *Config { 
} 

。我可以修改該配置,但我不能修改指向內部配置的指針。它非常接近Thing中的const指針。

+0

這就是爲什麼Go應該有const:P – allyourcode

+0

你不知道GetConfig返回相同的配置;只有當它不試圖訪問全球狀態E.g.系統的隨機數發生器。 – allyourcode

+0

複製不應被用來防止修改。它可以工作,但它具有顯着(隱藏)的性能成本。 – allyourcode

2

好像你總是希望這樣的:

號值接收器是比較一般。它可以用在指針接收器可以使用的所有地方;但指針接收器不能用於值接收器可以使用的所有地方 - 例如,如果您有一個類型爲Widget的右值表達式;你可以調用它的值接收器方法,但不能使用指針接收器方法。

+0

這似乎是一種反模式。看起來你的表達式應該是* Widget類型。否則,你可能最終會不知不覺地複製大量數據。 – allyourcode

+0

當你想修改對象本身時,你不能使用值接收器,對嗎?所以你不能*總是使用價值接收器。 – korylprince

+0

@korylprince:這不是我所說的「可以使用」的意思。我的意思是,由於你有一個帶有值接收器的方法和一個帶有指針接收器的方法,有一些表達式上下文你不能(在它不編譯的時候)使用帶指針接收器的方法,但是你可以在哪裏使用具有價值接受者的方法。當然,具有價值接收者的方法不能完成某些事情。但這不是問題的關鍵。這個問題提出了一個假設的價值接收方法,並詢問它是否應該始終作爲指針接收方。 – newacct