Menu

Array in Golang: lunghezza fissa, semantica per valore e slice

Un array Go ha una lunghezza fissa che fa parte del suo tipo e viene copiato quando lo assegni. Scopri come dichiarare, scorrere, confrontare e passare gli array, e perché la maggior parte del codice Go usa invece gli slice.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Dichiarare un array

Un tipo array si scrive [N]T: una lunghezza, poi un tipo di elemento. La lunghezza è fissata in fase di compilazione e fa parte del tipo.

Output:

[90 0 0 0 75] 5
Tue
[5]int [2 3 5 7 11]
["" "b" "" "d" ""]

Un array è sempre inizializzato del tutto. Gli elementi che non imposti contengono il valore zero del tipo dell'elemento: 0, "", false, nil.

Indici e limiti

Gli indici vanno da 0 a len(a)-1. Un indice costante fuori intervallo è un errore di compilazione. Un indice variabile fuori intervallo provoca un panic in fase di esecuzione.

var a [3]int
a[5] = 1 // compile error: invalid argument: index 5 out of bounds [0:3]

i := 5
a[i] = 1 // panic: runtime error: index out of range [5] with length 3

Scorrere un array

for i, v := range a visita ogni elemento in ordine. v è una copia dell'elemento, quindi assegnare un valore a v non modifica l'array. Scrivi invece tramite l'indice.

C'è un'altra sottigliezza tipica degli array: range su un valore array valuta subito una copia dell'array. Se il corpo del ciclo modifica gli elementi successivi, v mostra ancora i vecchi valori. Fare il range su &a o su a[:] evita la copia.

Gli array sono valori

Questa è la differenza principale rispetto agli array di C, Java o JavaScript. Assegnare un array copia ogni elemento. Anche passare un array a una funzione lo copia.

Output:

[1 2 3] [99 2 3]
[1 2 3]
[0 2 3]

La copia costa poco per gli array piccoli e molto per quelli grandi: passare un [1_000_000]int per valore copia otto megabyte. Passa un puntatore (*[N]T) o uno slice (a[:]) quando l'array è grande o quando la funzione deve modificarlo. Per accedere a un indice tramite un puntatore ad array non serve un * esplicito: a[0] funziona su un *[3]int.

Confrontare gli array e usarli come chiavi di una mappa

Gli array di elementi confrontabili supportano == e !=. Due array sono uguali quando ogni elemento è uguale. Questo li rende anche chiavi valide per una mappa, cosa che gli slice non sono.

Gli array di lunghezze diverse sono tipi diversi e non si possono proprio confrontare: [3]int{} == [4]int{} non compila (mismatched types [3]int and [4]int).

Array multidimensionali

Un array di array ti dà una griglia fissa. L'intera griglia è un unico blocco di memoria contiguo.

row[:] trasforma la riga [3]rune in uno slice []rune, che string() accetta.

Array e slice a confronto

Array [N]TSlice []T
Lunghezzafissa, fa parte del tipocambia con append
Assegnazione e passaggiocopia tutti gli elementicopia una piccola intestazione, condivide gli elementi
Valore zeroN elementi zeronil, lunghezza 0
==sì, elemento per elementosolo con nil
Chiave di una mappasìno
Uso tipicodati di dimensione fissa: hash, coordinate, bufferquasi tutto il resto

In pratica incontrerai gli array soprattutto in pochi punti: sha256.Sum256 restituisce un [32]byte, nelle tabelle di lookup la cui dimensione non cambia mai e come memoria sottostante di uno slice. Fare lo slicing di un array con a[:] o a[1:3] crea uno slice che ne condivide la memoria; la pagina sugli slice spiega cosa comporta questa condivisione.

Convertire tra array e slice

Convertire uno slice in un array (Go 1.20) o in un puntatore ad array (Go 1.17) provoca un panic se lo slice è più corto della lunghezza dell'array: panic: runtime error: cannot convert slice with length 2 to array or pointer to array with length 3.

Errori comuni

  • Aspettarsi che una funzione modifichi un array passato come argomento. Riceve una copia. Passa *[N]T o uno slice.
  • Usare un array dove serve uno slice. []int{1, 2} è uno slice, [2]int{1, 2} è un array. Una funzione che accetta []int non accetta un [2]int; passa a[:].
  • Array grandi in un ciclo range. for _, v := range bigArray prima copia l'intero array. Fai il range su &bigArray o su uno slice.

Domande frequenti

Come si dichiara un array in Go?

Scrivi la lunghezza tra parentesi quadre prima del tipo dell'elemento: var a [5]int crea cinque zeri. Con dei valori: a := [3]string{"x", "y", "z"}. Usa [...] per lasciare che sia il compilatore a contare: a := [...]int{1, 2, 3} ha tipo [3]int.

Qual è la differenza tra un array e uno slice in Go?

Un array ha una lunghezza fissa che fa parte del suo tipo ([3]int e [4]int sono tipi diversi) e viene copiato quando lo assegni o lo passi. Uno slice ([]int) è una vista su un array sottostante, con una lunghezza che può cambiare tramite append, e copiare uno slice copia solo la vista, non gli elementi. La maggior parte del codice Go usa gli slice.

Come ottengo la lunghezza di un array in Go?

Usa la funzione integrata len(a). Per un array è una costante nota in fase di compilazione, quindi puoi usarla nelle espressioni costanti. cap(a) restituisce lo stesso numero.

Si possono confrontare gli array in Go?

Sì, con == e !=, se il tipo degli elementi è confrontabile. Due array sono uguali quando tutti i loro elementi sono uguali. Gli array possono anche essere chiavi di una mappa. Gli slice non si possono confrontare con == (tranne che con nil); per loro usa slices.Equal.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA