Le strutture map e slice in Go presentano importanti caratteristiche di copia e semantica di gestione della memoria, che portano spesso a comportamenti imprevisti da parte di sviluppatori inesperti.
Sebbene Go sia considerato un linguaggio rigoroso con tipizzazione statica e senza puntatori per impostazione predefinita, map e slice hanno un modello interno speciale: entrambi i tipi sono strutture di riferimento. Questo comporta delle limitazioni e crea molte sfumature durante la copia e il passaggio di questi oggetti.
La copia di map e slice non porta a una copia profonda del contenuto, ma crea un nuovo riferimento allo stesso oggetto, il che porta a effetti collaterali inaspettati durante la modifica dei dati, il ritorno errato di valori dalle funzioni e le modifiche. Inoltre, restituire map o slice come risultato di una funzione può provocare ulteriori allocazioni o perdite di memoria.
b := a[:]). Per copiare completamente gli elementi, è necessario utilizzare la funzione incorporata copy().Esempio di copia corretta:
// Copia di un slice a := []int{1, 2, 3} b := make([]int, len(a)) copy(b, a) // b è ora indipendente da a // Copia di una map src := map[string]int{"x": 1} dst := make(map[string]int) for k, v := range src { dst[k] = v }
Caratteristiche chiave:
slice e map sono tipi di riferimento, vengono copiati tramite descrittore, non per contenutoCosa succede se assegno semplicemente una map/slice all'altra e poi modifico una delle due?
Sia la map che lo slice punteranno ai medesimi dati in memoria: la modifica influenzerà entrambi gli oggetti.
Perché quando restituiamo uno slice o una map da una funzione si dice spesso "è efficiente in termini di memoria"?
Perché viene restituita una copia del descrittore, non dell'intero contenuto; i dati nell'heap vivono fintanto che esistono riferimenti ad essi.
È possibile utilizzare la funzione copy() per effettuare una copia "profonda" di una map?
No, copy() funziona solo con slice e array; per le map è sempre necessario un ciclo.
Uno sviluppatore copia uno slice o una map tramite assegnazione e modifica la copia per proteggersi da effetti collaterali:
Vantaggi:
Svantaggi:
Prima di modificare i dati necessari, viene utilizzato copy() per lo slice e un ciclo per la map:
Vantaggi:
Svantaggi: