Gli slice in Go sono simili alle liste o agli array di altri linguaggi. Contengono diversi elementi di un tipo specifico (o di un'interface).
Gli slice in Go si basano sugli array. Gli array hanno una dimensione fissa. Uno slice, invece, è una vista flessibile e di dimensione dinamica sugli elementi di un array.
Uno slice si scrive come []T, dove T è il tipo degli elementi dello slice:
var empty []int // an empty slice
withData := []int{0,1,2,3,4,5} // a slice pre-filled with some data
Puoi leggere o impostare un elemento a un dato indice, che parte da zero, usando la notazione con le parentesi quadre ([]):
withData[1] = 5
x := withData[1] // x is now 5
Puoi creare un nuovo slice a partire da uno slice esistente estraendo un intervallo di elementi. Anche qui usi la notazione con le parentesi quadre, ma specificando sia un indice iniziale (incluso) sia un indice finale (escluso). Se non specifichi un indice iniziale, il valore predefinito è 0. Se non specifichi un indice finale, il valore predefinito è la lunghezza dello slice.
newSlice := withData[2:4]
// => []int{2,3}
newSlice := withData[:2]
// => []int{0,1}
newSlice := withData[2:]
// => []int{2,3,4,5}
newSlice := withData[:]
// => []int{0,1,2,3,4,5}
Puoi aggiungere elementi a uno slice usando la funzione append.
Qui sotto aggiungiamo 4 e 2 allo slice a.
a := []int{1, 3}
a = append(a, 4, 2)
// => []int{1,3,4,2}
append restituisce sempre un nuovo slice: quando vogliamo solo aggiungere elementi a uno slice esistente, di solito riassegniamo il risultato alla variabile dello slice che passiamo come primo argomento, come abbiamo fatto sopra.
append può anche essere usato per unire due slice:
nextSlice := []int{100,101,102}
newSlice := append(withData, nextSlice...)
// => []int{0,1,2,3,4,5,100,101,102}
Di solito, in Go le funzioni accettano solo un numero fisso di argomenti. Tuttavia, in Go è anche possibile scrivere funzioni variadiche.
Una funzione variadica è una funzione che accetta un numero variabile di argomenti.
Se il tipo dell'ultimo parametro nella definizione di una funzione è preceduto dai puntini di sospensione ..., allora la funzione può accettare un numero qualsiasi di argomenti per quel parametro.
func find(a int, b ...int) {
// ...
}
Nella funzione qui sopra, il parametro b è variadico e possiamo passare a b 0 o più argomenti.
find(5, 6)
find(5, 6, 7)
find(5)
Il parametro variadico deve essere l'ultimo parametro della funzione.
Le funzioni variadiche funzionano convertendo il numero variabile di argomenti in uno slice del tipo del parametro variadico.
Ecco un esempio di implementazione di una funzione variadica.
func find(num int, nums ...int) {
fmt.Printf("type of nums is %T\n", nums)
for i, v := range nums {
if v == num {
fmt.Println(num, "found at index", i, "in", nums)
return
}
}
fmt.Println(num, "not found in ", nums)
}
func main() {
find(89, 90, 91, 95)
// =>
// type of nums is []int
// 89 not found in [90 91 95]
find(45, 56, 67, 45, 90, 109)
// =>
// type of nums is []int
// 45 found at index 2 in [56 67 45 90 109]
find(87)
// =>
// type of nums is []int
// 87 not found in []
}
Nella riga find(89, 90, 91, 95) del programma qui sopra, il numero variabile di argomenti passati alla funzione find è 90, 91 e 95.
La funzione find si aspetta un parametro int variadico dopo num.
Quindi questi tre argomenti saranno convertiti dal compilatore in uno slice di tipo int, []int{90, 91, 95}, e poi passati alla funzione find come nums.
A volte hai già uno slice e vuoi passarlo a una funzione variadica.
Puoi farlo passando lo slice seguito da ....
Questo dice al compilatore di usare lo slice così com'è all'interno della funzione variadica.
In questo caso, il passaggio descritto sopra in cui viene creato uno slice viene semplicemente omesso.
list := []int{1, 2, 3}
find(1, list...) // "find" defined as shown above
Elyse, aspirante maga, deve fare pratica con alcune basi. Ha una pila di carte che vuole manipolare.
Per rendere le cose un po' più semplici, usa solo le carte dall'1 al 10.
Quando si esercita con le sue carte, Elyse preferisce iniziare con le sue tre carte preferite del mazzo: 2, 6 e 9.
Scrivi una funzione FavoriteCards che restituisce una slice con quelle carte in quell'ordine.
cards := FavoriteCards()
fmt.Println(cards)
// Output: [2 6 9]
Restituisci la carta alla posizione index della pila data.
card := GetItem([]int{1, 2, 4, 1}, 2) // card == 4
Se l'indice è fuori dai limiti (cioè se è negativo o oltre la fine della pila), vogliamo restituire -1:
card := GetItem([]int{1, 2, 4, 1}, 10) // card == -1
Per convenzione in Go, si restituisce un errore invece di restituire un valore «fuori dai limiti».
Qui il valore «fuori dai limiti» è -1 quando ci si aspetta un intero positivo.
Quando si restituisce un errore, è considerato idiomatico restituire lo zero value insieme all'errore.
Restituire un errore con il valore restituito corretto sarà trattato in un esercizio futuro.
Scambia la carta alla posizione index con la nuova carta fornita e restituisci la pila aggiornata.
Nota che questo modificherà la slice di input, che è il comportamento previsto.
index := 2
newCard := 6
cards := SetItem([]int{1, 2, 4, 1}, index, newCard)
fmt.Println(cards)
// Output: [1 2 6 1]
Se l'indice è fuori dai limiti (cioè se è negativo o oltre la fine della pila), vogliamo aggiungere la nuova carta in fondo alla pila:
index := -1
newCard := 6
cards := SetItem([]int{1, 2, 4, 1}, index, newCard)
fmt.Println(cards)
// Output: [1 2 4 1 6]
Aggiungi la carta (o le carte) specificate nel parametro value in cima alla pila.
slice := []int{3, 2, 6, 4, 8}
cards := PrependItems(slice, 5, 1)
fmt.Println(cards)
// Output: [5 1 3 2 6 4 8]
Se non viene fornito alcun argomento per il parametro value, il risultato è uguale alla slice originale.
slice := []int{3, 2, 6, 4, 8}
cards := PrependItems(slice)
fmt.Println(cards)
// Output: [3 2 6 4 8]
Rimuovi la carta alla posizione index dalla pila e restituisci la pila.
Nota che questo potrebbe modificare la slice di input, il che va bene.
cards := RemoveItem([]int{3, 2, 6, 4, 8}, 2)
fmt.Println(cards)
// Output: [3 2 4 8]
Se l'indice è fuori dai limiti (cioè se è negativo o oltre la fine della pila), vogliamo lasciare la pila invariata:
cards := RemoveItem([]int{3, 2, 6, 4, 8}, 11)
fmt.Println(cards)
// Output: [3 2 6 4 8]
Iscriviti a Exercism per imparare e padroneggiare Go con 34 concetti165 esercizi e il mentoring di persone reali, tutto gratis.