Quando si dichiara una variabile, in cui T
è un certo tipo:
var name T
Go ti dà un pezzo di non inizializzata "azzerato" memoria.
Con i primitivi, ciò significa che var name int
sarebbe 0 e var name string
sarebbe "". In C it might be zeroed, or might be something unexpected. Go garantisce che una variabile non inizializzata è equivalente a zero del tipo.
Internamente sezioni, mappe e canali vengono considerati come puntatori. Il valore zero dei puntatori è nullo, il che significa che punta a zero memoria. Senza inizializzarlo, puoi incontrare il panico se provi ad operare su di esso.
La funzione make
è specificamente progettata per una sezione, una mappa o un canale. Gli argomenti della funzione make sono:
make(T type, length int[, capacity int]) // For slices.
make(T[, capacity int]) // For a map.
make(T[, bufferSize int]) // For a channel. How many items can you take without blocking?
A fette length
è il numero di elementi che inizia con. La capacità è la memoria allocata prima che sia necessario un ridimensionamento (internamente, nuova dimensione * 2, quindi copia). Per ulteriori informazioni, vedere Effective Go: Allocation with make.
Strutturazioni: new(T)
equivale a &T{}
, non T{}
. *new(T)
equivale a *&T{}
.
Fette: make([]T,0)
è equivalente a []T{}
.
Mappe: make(map[T]T)
è equivalente a map[T]T{}
.
Per quanto riguarda quale metodo è preferito, mi pongo la seguente domanda:
conosco il valore (s) in questo momento all'interno della funzione?
Se la risposta è "sì", vado con uno dei precedenti T{...}
. Se la risposta è "no", allora uso make o new.
Per esempio, vorrei evitare qualcosa di simile:
type Name struct {
FirstName string
LastName string
}
func main() {
name := &Name{FirstName:"John"}
// other code...
name.LastName = "Doe"
}
Invece vorrei fare qualcosa di simile:
func main() {
name := new(Name)
name.FirstName = "John"
// other code...
name.LastName = "Doe"
}
Perché? Perché utilizzando new(Name)
ho chiarito che I intende per riempire i valori in seguito. Se avessi usato non sarebbe chiaro che intendevo aggiungere/modificare un valore più tardi nella stessa funzione senza leggere il resto del codice.
L'eccezione è con le strutture quando non si desidera un puntatore. Userò T{}
, ma non inserirò nulla se ho intenzione di aggiungere/modificare i valori. Ovviamente anche *new(T)
funziona, ma è come usare *&T{}
. T{}
è più pulito in questo caso, anche se io tendo ad usare i puntatori con le strutture per evitare di fare una copia quando lo faccio passare.
Un'altra cosa da tenere a mente, un []*struct
è più piccolo e più economico per ridimensionare rispetto []struct
, assumendo la struct è molto più grande di un puntatore, che in genere è di 4 - (? 8 byte su 64bit) 8 byte.
+1 Non risponde alla domanda, ma sono sicuro che sono d'accordo - felice di sapere che lo ha detto Pike stesso. Questa è una debolezza che sto riscontrando con GoLang: troppi modi per dichiarare e non chiarire i vantaggi e gli inconvenienti e l'appropriatezza di ciascuno di essi - mi dà talvolta una sensazione di "non proprio finito". – Vector