Maison > Article > développement back-end > Pourquoi `append()` de Golang semble-t-il modifier une tranche après son envoi sur un canal ?
Quand Golang append() crée-t-il une nouvelle tranche ?
La documentation pour append() indique qu'il allouera une nouvelle tranche et copier les éléments lorsque la capacité de la tranche d'origine est insuffisante. Cependant, une divergence survient lors de l'examen de la sortie du code suivant, qui génère des combinaisons d'un alphabet booléen.
<code class="go">package main import ( "fmt" ) func AddOption(c chan []bool, combo []bool, length int) { if length == 0 { fmt.Println(combo, "!") c <- combo return } var newCombo []bool for _, ch := range []bool{true, false} { newCombo = append(combo, ch) AddOption(c, newCombo, length-1) } } func main() { c := make(chan []bool) go func(c chan []bool) { defer close(c) AddOption(c, []bool{}, 4) }(c) for combination := range c { fmt.Println(combination) } }</code>
Observations contrastées
Dans la sortie, le les lignes se terminant par un point d'exclamation représentent les tranches envoyées sur le canal par AddOption, tandis que les lignes sans point d'exclamation montrent les tranches reçues dans main(). Il est à noter que les tranches envoyées sur le canal semblent avoir été modifiées après avoir été envoyées, bien que append() aurait renvoyé une nouvelle tranche.
Examen de la source
Le bloc de code douteux is :
<code class="go">var newCombo []bool for _, ch := range []bool{true, false} { newCombo = append(combo, ch) AddOption(c, newCombo, length-1) }</code>
Selon la documentation, append() devrait renvoyer un nouveau descripteur de tranche pointant vers un nouveau tableau de données sous-jacent lorsque la capacité de la tranche d'origine n'est pas suffisante. Cependant, la valeur transmise comme deuxième argument à AddOption peut être soit un pointeur vers un descripteur de tranche, soit une copie authentique du descripteur de tranche.
Clarification du comportement
La réponse à cette question réside dans la distinction entre le type de données slice et sa représentation réelle. Un descripteur de tranche se compose de deux entiers pour la longueur et la capacité, ainsi que d'un pointeur vers les données sous-jacentes.
Bien que append() renvoie un nouveau descripteur de tranche avec un tableau de données sous-jacent potentiellement différent, le pointeur vers les données reste la même à moins que la capacité soit augmentée. Cela signifie que même si le descripteur de tranche lui-même est une copie, la valeur du pointeur (adresse des données sous-jacentes) est partagée.
Exemple supplémentaire
À titre d'illustration, considérons ceci extrait de code :
<code class="go">package main import "fmt" func main() { s := make([]int, 0, 5) s = append(s, []int{1, 2, 3, 4}...) a := append(s, 5) fmt.Println(a) b := append(s, 6) fmt.Println(b) fmt.Println(a) }</code>
Ce code s'imprime :
[1 2 3 4 5] [1 2 3 4 6] [1 2 3 4 6]
Initialement, s a suffisamment de capacité, donc a et b partagent le même pointeur de données sous-jacent. Cependant, si nous réduisons la capacité de s à 4, le résultat devient :
[1 2 3 4 5] [1 2 3 4 6] [1 2 3 4 5]
Cela démontre que a et b ne partagent les mêmes données sous-jacentes que lorsque s a une capacité suffisante.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!