Maison >développement back-end >Golang >Comment Go gère-t-il les variables de boucle capturées dans les fermetures et pourquoi est-ce important ?

Comment Go gère-t-il les variables de boucle capturées dans les fermetures et pourquoi est-ce important ?

Mary-Kate Olsen
Mary-Kate Olsenoriginal
2024-12-15 11:56:10805parcourir

How Does Go Handle Captured Loop Variables in Closures, and Why Does it Matter?

Fermeture capturée (pour variable de boucle) dans Go

Comprendre les fermetures de variables de boucle

Dans Go, le compilateur peut capturer automatiquement les variables de boucle pour les utiliser dans fermetures, mais ce comportement varie en fonction du type de boucle. Dans les boucles for...range, les variables de boucle sont capturées comme références aux variables d'itération de la boucle externe.

Raison des fermetures de référence dans les boucles for...range

Go traite for.. Boucles .range et autres boucles for de la même manière. Par conséquent, la fermeture capturée pour une variable de boucle dans une boucle for...range fait référence au même emplacement mémoire que la variable de la boucle externe.

Conséquences des fermetures de référence

Dans ce scénario, toute modification apportés à la variable de fermeture capturée affectent également la variable de la boucle externe, conduisant potentiellement à un comportement inattendu. Pour éviter ce problème, il est nécessaire de créer une copie de la variable de boucle dans la fermeture, comme indiqué dans l'exemple « Valeur...plage » ci-dessous.

Exemple de code

Le code fourni L'extrait illustre la différence entre capturer une référence à la variable de boucle et capturer sa valeur :

func main() {
    lab1() // captured closure is not what is expected

    lab2() // captured closure is not what is expected

    lab3() // captured closure behaves ok
}

func lab3() {
    m := make(map[int32]int32)
    for i := 1; i <= 10; i++ {
        m[i] = i
    }

    l := [](func() (int32, int32)){}
    for k, v := range m {
        kLocal, vLocal := k, v // (C) captures just the right values assigned to k and v
        l = append(l, func() (int32, int32) {
            return kLocal, vLocal
        })
    }

    for _, x := range l {
        k, v := x()
        fmt.Println(k, v)
    }
}

func lab2() {
    m := make(map[int32]int32)
    for i := 1; i <= 10; i++ {
        m[i] = i
    }

    l := [](func() (int32, int32)){}
    for k, v := range m {
        l = append(l, func() (int32, int32) {
            kLocal, vLocal := k, v // (B) captures just the last values assigned to k and v from the range
            return kLocal, vLocal
        })
    }

    for _, x := range l {
        k, v := x()
        fmt.Println(k, v)
    }
}

func lab1() {
    m := make(map[int32]int32)
    for i := 1; i <= 10; i++ {
        m[i] = i
    }

    l := [](func() (int32, int32)){}
    for k, v := range m {
        l = append(l, func() (int32, int32) { return k, v }) // (A) captures just the last values assigned to k and v from the range
    }

    for _, x := range l {
        k, v := x()
        fmt.Println(k, v)
    }
}

Sortie

In lab1, les fermetures capturées font référence aux valeurs finales de la boucle au lieu des valeurs individuelles attendues. Dans Lab2, les captures font toujours référence aux valeurs finales car la fermeture créée utilise les mêmes variables de boucle qui sont référencées ailleurs dans la portée externe. Dans Lab3, les fermetures capturent des copies des variables de boucle, elles représentent donc avec précision les valeurs individuelles.

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