通過值或指針訪問另一個結構時有什麼不同?
什麼時候應該使用它們中的每一個?通過值或指針訪問另一個結構
type foo_ struct {
st uint8
nd uint8
}
type bar struct {
rd uint8
foo foo_
}
type barP struct {
rd uint8
foo *foo_
}
通過值或指針訪問另一個結構時有什麼不同?
什麼時候應該使用它們中的每一個?通過值或指針訪問另一個結構
type foo_ struct {
st uint8
nd uint8
}
type bar struct {
rd uint8
foo foo_
}
type barP struct {
rd uint8
foo *foo_
}
如果聲明或分配變量type bar
,則爲rd uint8
和foo foo_
預留和初始化爲零內存。總是有一個變量type foo_
嵌入在變量type bar
中。
var b bar // declare b
如果聲明或分配的type barP
變量,則保留並初始化爲零內存都rd uint8
和foo *foo_
。一個零值指針是一個nil
指針。沒有分配type foo_
的變量;你必須分開做。有一個變量爲type barP
的零(foo == nil
)或一個變量type foo_
。變量type barP
可指向與type barP
的其他變量type foo_
相同的變量,共享變量type foo_
的相同副本。指向它的所有變量都會看到對共享副本的更改。
var bp barP // declare bp
bp.foo = new(foo_) // allocate bp.foo
使用哪一個取決於type bar
與type barP
屬性。哪種類型更能反映你正試圖解決的問題?
例如,考慮此發票問題。我們總是有一個帳單地址;我們總是會要求我們的錢。但是,我們經常會發送到帳單地址,但並非總是如此。如果送貨地址是nil
,請使用帳單地址。否則,請使用單獨的送貨地址。我們有兩個倉庫,我們總是從一個倉庫出貨。我們可以共享這兩個倉庫位置。由於在訂單從倉庫發貨前我們不發送發票,所以倉庫地址永遠不會是nil
。
type address struct {
street string
city string
}
type warehouse struct {
address string
}
type invoice struct {
name string
billing address
shipping *address
warehouse *warehouse
}
答案在很大程度上與語言無關 - 在C中的等價物具有相同的問題。
如果您擁有嵌入式值(如bar
),那麼您的結構足夠大以容納完整的子結構和其他部分。
如果您有一個指向值的指針(如在barP
中),則barP
類型的許多結構可能共享相同的foo
。當barP
中的任何一個修改它指向的foo
的一部分時,它會影響指向相同位置的所有其他barP
結構。另外,正如評註所暗示的那樣,您必須管理兩個單獨的對象 - barP
和foo
,而不是簡單的bar
類型。
在某些語言中,你將不得不擔心懸掛指針和未初始化值等; Go是垃圾收集,通常比其他語言更安全。
所以,當你想要多個barP
對象共享相同的foo
對象時使用指針;否則,使用顯式成員對象,而不是指向對象的指針。
的Golang FAQ現在總結的區別:
func (s *MyStruct) pointerMethod() { } // method on pointer
func (s MyStruct) valueMethod() { } // method on value
首先,也是最重要的,確實的方法需要修改接收器?
如果是這樣,接收器必須是一個指針。 (切片和地圖是參考類型,所以他們的故事稍微微妙一些,但是例如在一種方法中改變切片的長度,接收器必須仍然是一個指針。)
在上面的例子中,如果pointerMethod
修改了字段s
,調用者將看到這些更改,但valueMethod
被調用者的參數副本調用(這是傳遞值的定義),因此調用者不會看到它的更改。
順便提一句,指針接收器與Java中的情況相同,但在Java中,指針隱藏在封面之下;這是Go的價值接受者是不尋常的。二是考慮效率。如果接收器很大,例如一個大結構,使用指針接收器會便宜得多。
(此效率點也適用於 「Memory, variables in memory, and pointers」 示出)
接下來是一致性。如果某些類型的方法必須具有指針接收器,則其餘的方法也應該如此,因此無論類型如何使用,方法集都是一致的。詳情請參閱method sets一節。
當聲明或分配'type barP'的變量時,foo的初始值將是'nil'指針。 – peterSO 2010-05-03 00:43:48