In Go, per impostazione predefinita, tutti gli argomenti delle funzioni vengono trasmessi per valore: viene copiato il valore della variabile. Ma alcuni tipi (come slice, mappe, canali) sono «wrapper» su strutture interne (puntatori). La trasmissione di uno slice per valore copia solo il descrittore dello slice e non i dati; entrambe le variabili puntano allo stesso array. Nel caso delle strutture, viene copiata l'intera struttura.
Se è necessario evitare la copia e lavorare con l'originale, si utilizza la trasmissione per puntatore (*Struct).
type User struct { Name string Age int } func updateUser(u User) { u.Age = 30 // modifica solo la copia } func updateUserPtr(u *User) { u.Age = 30 // modifica l'originale } func main() { u := User{"Ivan", 25} updateUser(u) fmt.Println(u.Age) // 25 updateUserPtr(&u) fmt.Println(u.Age) // 30 }
Le modifiche a uno slice passato a una funzione sono sempre visibili al di fuori della funzione?
No!
slice[i] = ...), è visibile al di fuori.slice = append(slice, ...)), e il risultato non viene restituito dalla funzione, i nuovi elementi saranno in una copia locale e verranno persi.func addElem(s []int) { s = append(s, 100) } func main() { arr := []int{1,2,3} addElem(arr) fmt.Println(arr) // [1 2 3] — 100 non è stato aggiunto }
Storia
In uno dei progetti, le strutture dati con un grande campo struct (200+ byte) venivano passate per valore attraverso i canali tra le goroutine, causando enormi sovraccarichi di copia e perdite di prestazioni. Dopo essere passati a una trasmissione per puntatore, la latenza è diminuita di un ordine di grandezza.
Storia
In un servizio di log audit, uno sviluppatore passava una mappa (map) tra funzioni senza una clonazione esplicita (copy). Le modifiche apportate da una funzione cambiavano inaspettatamente i dati in un'altra parte del programma, causando confusione nel log.
Storia
Nella funzione di aumento dinamico dello slice, all'interno della funzione è stato dimenticato di restituire il nuovo slice. Di conseguenza, le modifiche non sono state riflesse nel codice chiamante, portando alla perdita di parte delle transazioni. È stato deciso di restituire il nuovo slice dalla funzione.