ProgrammazioneSviluppatore Backend Go

Descrivi le caratteristiche della copia di slice e struct in Go. Come evitare effetti indesiderati quando si lavora con essi?

Supera i colloqui con l'assistente IA Hintsage

Risposta

Le struct in Go vengono copiate per valore (deep copy di primo livello, le struct annidate vengono copiate secondo la stessa regola), mentre gli slice vengono copiati per valore, ma viene copiata solo la struttura e non l'array sottostante: sia l'originale che la copia dello slice puntano allo stesso backing array, quindi una modifica tramite uno slice si rifletterà nell'altro, a meno che non si faccia una copia esplicita dell'array tramite copy().

Esempio di copia di uno slice:

s1 := []int{1,2,3} s2 := s1 // puntatori allo stesso buffer! s2[0] = 99 fmt.Println(s1) // [99 2 3] // Per la copia dell'array: s3 := make([]int, len(s1)) copy(s3, s1) s3[0] = 42 fmt.Println(s1) // [99 2 3], s3 è indipendente

Quando si copiano le struct: se la struct contiene un campo puntatore o un campo slice, vengono copiate solo le referenze, non i valori.

Domanda-trappola

Qual è il modo per "clonare" uno slice in modo che le sue modifiche non influenzino l'originale?

Risposta potenzialmente errata: basta fare b := a. Corretto:

  • Bisogna usare copy, creare un nuovo slice della lunghezza necessaria e copiare i dati:
newS := make([]int, len(a)) copy(newS, a)

Esempi di errori reali a causa della mancanza di conoscenza delle sfumature dell'argomento


Storia

Descrizione: Durante la generazione di query al DB, si cambiavano dinamicamente i campi dello slice nella struct della query, senza fare copie. Durante le richieste successive i dati si sovrapponevano, restituendo risultati imprecisi per gli utenti.


Storia

Descrizione: Durante l'elaborazione parallela dei dati, si creava una copia della struct tramite assegnazione e si espandeva lo slice in una goroutine, utilizzando contemporaneamente un altro slice originale. I dati venivano "sovrascritti", portando a bug imprevedibili.


Storia

Descrizione: Si utilizzava una struct buffer, la copia simultanea tramite assegnazione non considerava gli slice annidati (shallow copy), le modifiche in un luogo influenzavano un altro buffer - alla fine era difficile rintracciare la fonte della modifica dei dati.