La funzione make in Go è utilizzata esclusivamente per inizializzare oggetti di tipo: slice, map e channel. Essa alloca la struttura dati necessaria e restituisce un oggetto pronto per l'uso (non un puntatore!).
Esempi:
s := make([]int, 5, 10) // slice di lunghezza 5, capacità 10 m := make(map[string]int) // mappa vuota ch := make(chan int, 2) // canale bufferizzato di 2
Particolarità:
slice i parametri sono: lunghezza (len) e (opzionale) capacità (cap).map e chan — solo (opzionale) capacità (dimensione iniziale/buffer).make restituisce già un oggetto inizializzato, pronto per l'uso.make non viene utilizzato, vengono inizializzati usando i letterali o new (che restituisce un puntatore al valore zero).Confronto con new:
new(T) restituisce *T, dove tutti i campi sono nulli.make(T) restituisce T solo per tre tipi: slice, map, chan.È possibile ottenere una mappa funzionante tramite new invece di make?
m := new(map[string]int) (*m)["a"] = 1 // Cosa succederà?
Molti pensano che questo sia corretto, ma si verificherà un panic a runtime: assignment to entry in nil map. Perché nella variabile *m c'è nil!
Corretto: usare make:
m := make(map[string]int) m["a"] = 1 // OK
Storia
In un microservizio per la memorizzazione della cache, si creava una mappa tramite var cache map[string]interface{} senza inizializzazione make, il che causava panic in production durante la scrittura con stack trace incomprensibili. Il problema è stato individuato solo dopo l'analisi del codice: la mappa era nil.
Storia
Scrivendo un pipeline dati, si è dimenticati del buffer nel canale e si è creato tramite make(chan int). Di conseguenza, le goroutine si bloccavano in attesa di lettura, anche se ci si aspettava uno scambio asincrono. L'errore è stato notato solo durante un test su larga scala.
Storia
In un progetto dove l'inizializzazione avveniva tramite new, alcuni sviluppatori cercavano di usare new([]int) invece di make([]int, 10), ottenendo così un puntatore a slice nil e panic a runtime ai primi tentativi di scrittura.