Maison >développement back-end >Golang >Pourquoi `append()` de Golang semble-t-il modifier une tranche après son envoi sur un canal ?

Pourquoi `append()` de Golang semble-t-il modifier une tranche après son envoi sur un canal ?

Linda Hamilton
Linda Hamiltonoriginal
2024-11-02 10:01:31352parcourir

Why Does Golang's `append()` Seem to Modify a Slice After It's Sent Over a Channel?

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn