2010-05-02 53 views
6

通過值或指針訪問另一個結構時有什麼不同?
什麼時候應該使用它們中的每一個?通過值或指針訪問另一個結構

type foo_ struct { 
    st uint8 
    nd uint8 
} 

type bar struct { 
    rd uint8 
    foo foo_ 
} 

type barP struct { 
    rd uint8 
    foo *foo_ 
} 

回答

5

如果聲明或分配變量type bar,則爲rd uint8foo foo_預留和初始化爲零內存。總是有一個變量type foo_嵌入在變量type bar中。

var b bar // declare b 

如果聲明或分配的type barP變量,則保留並初始化爲零內存都rd uint8foo *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 bartype 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 
} 
2

答案在很大程度上與語言無關 - 在C中的等價物具有相同的問題。

如果您擁有嵌入式值(如bar),那麼您的結構足夠大以容納完整的子結構和其他部分。

如果您有一個指向值的指針(如在barP中),則barP類型的許多結構可能共享相同的foo。當barP中的任何一個修改它指向的foo的一部分時,它會影響指向相同位置的所有其他barP結構。另外,正如評註所暗示的那樣,您必須管理兩個單獨的對象 - barPfoo,而不是簡單的bar類型。

在某些語言中,你將不得不擔心懸掛指針和未初始化值等; Go是垃圾收集,通常比其他語言更安全。

所以,當你想要多個barP對象共享相同的foo對象時使用指針;否則,使用顯式成員對象,而不是指向對象的指針。

+1

當聲明或分配'type barP'的變量時,foo的初始值將是'nil'指針。 – peterSO 2010-05-03 00:43:48

2

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一節。

相關問題