2010-05-02 11 views

risposta

5

Se si dichiara o si assegna una variabile di type bar, si riserva e si inizializza a zero memoria per rd uint8 e foo foo_. C'è sempre una variabile di type foo_ incorporata in una variabile di type bar.

var b bar // declare b 

Se si dichiara o allocare una variabile di type barP, le prenotazioni e inizializzare la memoria zero per entrambi rd uint8 e foo *foo_. Un puntatore a valore zero è un puntatore nil. Nessuna variabile di type foo_ è allocata; devi farlo separatamente. Vi è uno zero (foo == nil) o una variabile di type foo_ indicata da una variabile di type barP. Una variabile di type barP può puntare alla stessa variabile di type foo_ come altre variabili di type barP, condividendo la stessa copia della variabile di type foo_. Una modifica a una copia condivisa è vista da tutte le variabili che puntano ad essa.

var bp barP   // declare bp 
bp.foo = new(foo_) // allocate bp.foo 

quale usare dipende dalle proprietà dei type bar contro type barP. Quale tipo riflette più da vicino il problema che stai cercando di risolvere?

Ad esempio, considerare questo problema di fatturazione. Abbiamo sempre un indirizzo di fatturazione; chiederemo sempre i nostri soldi Tuttavia, spesso spediamo all'indirizzo di fatturazione, ma non sempre. Se l'indirizzo di spedizione è nil, utilizzare l'indirizzo di fatturazione. Altrimenti, utilizzare un indirizzo di spedizione separato. Abbiamo due magazzini e spediamo sempre da uno o dall'altro. Possiamo condividere le due posizioni di magazzino. Poiché non inviamo una fattura fino a quando l'ordine non viene spedito dal magazzino, la posizione di magazzino non sarà mai 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

La risposta è in gran parte indipendente dalla lingua: l'equivalente in C ha gli stessi problemi.

Se si dispone di un valore incorporato (come in bar), la struttura è sufficientemente grande da contenere la sottostruttura completa e l'altra parte.

Quando si ha un puntatore a un valore (come in barP), quindi un numero di strutture di tipo barP può condividere lo stesso foo. Quando uno qualsiasi dei barP modifica una parte di foo a cui fa riferimento, interessa tutte le altre strutture barP che puntano allo stesso punto. Inoltre, come suggerisce il commento, devi gestire due oggetti separati: lo barP e lo foo come uno con il tipo normale bar.

In alcune lingue, ci si dovrebbe preoccupare di puntatori penzolanti e valori non inizializzati ecc; Go è garbage collection e generalmente più sicuro per il tipo rispetto ad altre lingue.

Quindi, utilizzare un puntatore quando si desidera che più oggetti barP condividano lo stesso oggetto foo; altrimenti, utilizzare un oggetto membro esplicito, piuttosto che un puntatore a un oggetto.

+1

Quando una variabile di tipo barP' è dichiarata o allocata, il valore iniziale di foo sarà un puntatore 'nil'. – peterSO

2

Il Golang FAQ ora riassume la differenza tra:

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

In primo luogo, e più importante, fa il metodo necessario modificare il ricevitore?
In caso affermativo, il ricevitore deve essere un puntatore. (Le fette e le mappe sono tipi di riferimento, quindi la loro storia è un po 'più sottile, ma per esempio per cambiare la lunghezza di una sezione in un metodo il ricevitore deve essere ancora un puntatore.)
Negli esempi precedenti, se pointerMethod modifica il valore campi di s, il chiamante vedrà quelle modifiche, ma valueMethod viene chiamato con una copia dell'argomento del chiamante (che è la definizione di passare un valore), quindi le modifiche apportate saranno invisibili al chiamante.
A proposito, i destinatari del puntatore sono identici alla situazione in Java, sebbene in Java i puntatori siano nascosti sotto le copertine; sono i ricevitori di valore di Go che sono inusuali.

Secondo è la considerazione dell'efficienza . Se il ricevitore è grande, ad esempio una grande struttura, sarà molto più economico usare un ricevitore puntatore.

(Questo punto è illustrato efficienza anche in "Memory, variables in memory, and pointers")

successivo è consistenza. Se alcuni dei metodi del tipo devono avere ricevitori di puntatori, anche il resto dovrebbe esserlo, quindi il set di metodi è coerente indipendentemente da come viene utilizzato il tipo. Vedere la sezione su method sets per i dettagli.

Problemi correlati