Catégories
Programmation

Subtilité sur les tableaux supports des slices en Go

Si vous êtes un adepte des slices en Go voici une petite subtilité sur laquelle il faut faire attention.

Code exemple

Analyser dans votre tête le code suivant. On crée un slice puis un slice de slice et on modifie et ajoute des valeurs.
Concentrez-vous sur la dernière instruction. Qu’affiche s1 et s2 ?

package main

import (
	"fmt"
)

func main() {
	s1 := make([]int, 3, 4)
	fmt.Println("s1:", s1)
	s2 := s1[1:2]
	fmt.Println("s2:", s2)

	fmt.Println("# s2[0] = 1")
	s2[0] = 1
	fmt.Println("s1:", s1)
	fmt.Println("s2:", s2)

	fmt.Println("# append(s2, 2)")
	s2 = append(s2, 2)
	fmt.Println("s1:", s1)
	fmt.Println("s2:", s2)

	fmt.Println("# s2[1] = 9")
	s2[1] = 9
	fmt.Println("s1:", s1)
	fmt.Println("s2:", s2)

	fmt.Println("# append(s2, 3)")
	s2 = append(s2, 3)
	fmt.Println("s1:", s1)
	fmt.Println("s2:", s2)

	fmt.Println("# s2[1] = 8")
	s2[1] = 8
	fmt.Println("s1:", s1)
	fmt.Println("s2:", s2)

	fmt.Println("# append(s2, 4)")
	s2 = append(s2, 4)
	fmt.Println("s1:", s1)
	fmt.Println("s2:", s2)

	fmt.Println("# s2[1] = 7")
	s2[1] = 7
	fmt.Println("s1:", s1)
	fmt.Println("s2:", s2)
}

Voici la sortie

s1: [0 0 0]
s2: [0]
# s2[0] = 1
s1: [0 1 0]
s2: [1]
# append(s2, 2)
s1: [0 1 2]
s2: [1 2]
# s2[1] = 9
s1: [0 1 9]
s2: [1 9]
# append(s2, 3)
s1: [0 1 9]
s2: [1 9 3]
# s2[1] = 8
s1: [0 1 8]
s2: [1 8 3]
# append(s2, 4)
s1: [0 1 8]
s2: [1 8 3 4]
# s2[1] = 7
s1: [0 1 8]
s2: [1 7 3 4]

Explication

Pourquoi la dernière modification à 7 n’est effective que sur s2 ?

Pour comprendre l’explication, il faut revenir au support des slices : les tableaux.
En Go, les slices sont « supportés » par des tableaux et lors de la création du slice s1, nous avons spécifié un slice de capacité 4 (ligne 8), Go a donc créé un tableau support de 4 espaces mémoire pour des types int.
Le slice s2 provenant du slice s1, il utilise le même tableau en interne mais lors de l’ajout de la ligne 39, ce tableau n’est plus assez grand pour supporter un cinquième élément (Liloo multi-pass), Go réserve donc un tableau plus grand, recopie les 4 premiers éléments et insère le cinquième dans le nouveau tableau.

s1 utilise le tableau original mais s2 utilise maintenant un second tableau, plus grand. Lors de la modification de s2 à la ligne 44, seul le second tableau est affecté. L’affichage de s1 ne reflète donc pas cette modification et c’est normal.

Bien subtil, n’est-ce pas ?

Liens

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *