Les slices en Go sont similaires aux tableaux dans d'autres langages. Ils contiennent plusieurs éléments d'un type spécifique (ou d'une interface).
Les slices en Go sont basés sur les tableaux. Les tableaux ont une taille fixe. Un slice, quant à lui, est une vue flexible et de taille dynamique des éléments d'un tableau.
Un slice s'écrit comme []T, où T est le type des éléments du slice :
var empty []int // an empty slice
withData := []int{0,1,2,3,4,5} // a slice pre-filled with some data
On peut obtenir ou définir un élément à un indice donné (en partant de zéro) en utilisant la notation entre crochets :
withData[1] = 5
x := withData[1] // x is now 5
On peut créer un nouveau slice à partir d'un slice existant en récupérant une plage d'éléments. Là encore, on utilise la notation entre crochets, mais en précisant un indice de début (inclus) et un indice de fin (exclu). Si l'on ne précise pas d'indice de début, il vaut 0 par défaut. Si l'on ne précise pas d'indice de fin, il vaut par défaut la longueur du 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}
On peut ajouter des éléments à un slice avec la fonction append.
Ci-dessous, on ajoute 4 et 2 au slice a.
a := []int{1, 3}
a = append(a, 4, 2)
// => []int{1,3,4,2}
append renvoie toujours un nouveau slice, et lorsqu'on veut simplement ajouter des éléments à un slice existant, il est courant de le réaffecter à la variable de slice que l'on passe en premier argument, comme ci-dessus.
append peut aussi servir à fusionner deux slices :
nextSlice := []int{100,101,102}
newSlice := append(withData, nextSlice...)
// => []int{0,1,2,3,4,5,100,101,102}
En général, les fonctions en Go n'acceptent qu'un nombre fixe d'arguments. Il est toutefois possible d'écrire des fonctions variadiques en Go.
Une fonction variadique est une fonction qui accepte un nombre variable d'arguments.
Si le type du dernier paramètre dans la définition d'une fonction est précédé de points de suspension ..., alors la fonction peut accepter n'importe quel nombre d'arguments pour ce paramètre.
func find(a int, b ...int) {
// ...
}
Dans la fonction ci-dessus, le paramètre b est variadique et on peut passer 0 argument ou plus à b.
find(5, 6)
find(5, 6, 7)
find(5)
Le paramètre variadique doit être le dernier paramètre de la fonction.
Les fonctions variadiques fonctionnent en convertissant le nombre variable d'arguments en un slice du type du paramètre variadique.
Voici un exemple d'implémentation d'une fonction variadique.
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 []
}
À la ligne find(89, 90, 91, 95) du programme ci-dessus, les arguments en nombre variable passés à la fonction find sont 90, 91 et 95.
La fonction find attend un paramètre int variadique après num.
Par conséquent, ces trois arguments seront convertis par le compilateur en un slice de type int, []int{90, 91, 95}, puis passés à la fonction find sous le nom nums.
Parfois, on a déjà un slice et on veut le passer à une fonction variadique.
On y parvient en passant le slice suivi de ....
Cela indique au compilateur d'utiliser le slice tel quel à l'intérieur de la fonction variadique.
L'étape décrite ci-dessus, où un slice est créé, est simplement omise dans ce cas.
list := []int{1, 2, 3}
find(1, list...) // "find" defined as shown above
En apprentie magicienne, Elyse doit s'entraîner sur quelques bases. Elle a une pile de cartes qu'elle veut manipuler.
Pour que ce soit un peu plus simple, elle n'utilise que les cartes de 1 à 10.
Quand elle s'entraîne avec ses cartes, Elyse aime commencer par ses trois cartes préférées du jeu : 2, 6 et 9.
Écris une fonction FavoriteCards qui renvoie un slice contenant ces cartes dans cet ordre.
cards := FavoriteCards()
fmt.Println(cards)
// Output: [2 6 9]
Renvoie la carte à la position index de la pile donnée.
card := GetItem([]int{1, 2, 4, 1}, 2) // card == 4
Si l'indice est hors limites (c'est-à-dire s'il est négatif ou au-delà de la fin de la pile), on veut renvoyer -1 :
card := GetItem([]int{1, 2, 4, 1}, 10) // card == -1
Par convention en Go, on renvoie une erreur plutôt qu'une valeur « hors limites ».
Ici, la valeur « hors limites » est -1 alors qu'on attend un entier positif.
Quand on renvoie une erreur, il est considéré comme idiomatique de renvoyer la zero value avec l'erreur.
Renvoyer une erreur accompagnée de la valeur de retour appropriée sera abordé dans un prochain exercice.
Échange la carte à la position index avec la nouvelle carte fournie et renvoie la pile modifiée.
Note que cela modifie le slice d'entrée, ce qui est le comportement attendu.
index := 2
newCard := 6
cards := SetItem([]int{1, 2, 4, 1}, index, newCard)
fmt.Println(cards)
// Output: [1 2 6 1]
Si l'indice est hors limites (c'est-à-dire s'il est négatif ou au-delà de la fin de la pile), on veut ajouter la nouvelle carte à la fin de la pile :
index := -1
newCard := 6
cards := SetItem([]int{1, 2, 4, 1}, index, newCard)
fmt.Println(cards)
// Output: [1 2 4 1 6]
Ajoute la ou les cartes indiquées dans le paramètre value au sommet de la pile.
slice := []int{3, 2, 6, 4, 8}
cards := PrependItems(slice, 5, 1)
fmt.Println(cards)
// Output: [5 1 3 2 6 4 8]
Si aucun argument n'est fourni pour le paramètre value, le résultat est égal au slice d'origine.
slice := []int{3, 2, 6, 4, 8}
cards := PrependItems(slice)
fmt.Println(cards)
// Output: [3 2 6 4 8]
Retire la carte à la position index de la pile et renvoie la pile.
Note que cela peut modifier le slice d'entrée, ce qui n'est pas un problème.
cards := RemoveItem([]int{3, 2, 6, 4, 8}, 2)
fmt.Println(cards)
// Output: [3 2 4 8]
Si l'indice est hors limites (c'est-à-dire s'il est négatif ou au-delà de la fin de la pile), on veut laisser la pile inchangée :
cards := RemoveItem([]int{3, 2, 6, 4, 8}, 11)
fmt.Println(cards)
// Output: [3 2 6 4 8]
Inscris-toi sur Exercism pour apprendre et maîtriser Go avec 34 concepts165 exercices, et un vrai mentorat humain, le tout gratuitement.