ProgrammazioneSviluppatore Go

Spiega le peculiarità della funzione integrata make in Go: quando è necessaria, come funziona l'inizializzazione del slicing per map, slice e channel? Quali errori si possono verificare a causa di un uso scorretto di make e new?

Supera i colloqui con l'assistente IA Hintsage

Risposta

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à:

  • Per slice i parametri sono: lunghezza (len) e (opzionale) capacità (cap).
  • Per map e chan — solo (opzionale) capacità (dimensione iniziale/buffer).
  • La funzione make restituisce già un oggetto inizializzato, pronto per l'uso.
  • Per altri tipi (struct, array) 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.

Domanda insidiosa

È 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

Esempi di errori reali a causa della mancanza di conoscenza delle sfumature del tema


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.