Maison >développement back-end >Golang >Pourquoi la boucle « for range » de Go présente-t-elle un comportement différent avec les littéraux de fonction ?

Pourquoi la boucle « for range » de Go présente-t-elle un comportement différent avec les littéraux de fonction ?

Susan Sarandon
Susan Sarandonoriginal
2024-12-10 20:52:11428parcourir

Why Does Go's `for range` Loop Exhibit Different Behavior with Function Literals?

Comprendre le comportement des différentes boucles dans Go

Lors de la construction de boucles dans Go, il est crucial de comprendre le comportement de la boucle for range. Considérez les deux variantes de boucle suivantes qui présentent un comportement distinct :

Variation de boucle 1 :

func loop1() {

    actions := make(map[string]func())

    for _, cmd := range cmds {
        actions[cmd] = func() {
            fmt.Println(cmd)
        }
    }
    for _, action := range actions {
        action()
    }
}

Variation de boucle 2 :

func loop2() {

    actions := make(map[string]func())

    for i, cmd := range cmds {
        command := cmds[i]
        actions[cmd] = func() {
            fmt.Println(command)
        }
    }
    for _, action := range actions {
        action()
    }
}

Sortie Observations :

  • La boucle 1 produit une sortie : "mettre à jour" (répétée 3 fois)
  • La boucle 2 produit une sortie : "supprimer", "mettre à jour", "créer"

Problème sous-jacent dans la variation de boucle 1 :

Le problème réside dans la boucle func loop1(). Chaque itération de boucle attribue un littéral de fonction à la carte d'actions. Ce littéral de fonction fait référence à la variable de boucle cmd. Cependant, il n’existe qu’une seule instance de cmd et, lorsque la boucle se termine, elle contient la dernière valeur de la tranche de commandes, qui est « update ». Cela signifie que toutes les fonctions incluses font référence à la même variable de boucle (cmd), ce qui entraîne l'impression de "mise à jour" par toutes les fonctions lorsqu'elles sont appelées.

Solution :

Pour rectifier ce problème , faites une copie de la variable de boucle dans chaque itération de boucle, afin que chaque littéral de fonction ait son propre indépendant copy :

func loop1() {
    actions := make(map[string]func())

    for _, cmd := range cmds {
        cmd2 := cmd
        actions[cmd] = func() {
            fmt.Println(cmd2) // Refer to the detached, copy variable!
        }
    }
    for _, action := range actions {
        action()
    }
}

Conclusion :

En conclusion, lors de l'utilisation de la boucle for range, il est essentiel de prendre en compte la portée et les références des variables de boucle. S'assurer que des copies des variables de boucle sont effectuées lorsque cela est nécessaire garantit un comportement correct, en particulier lorsqu'il s'agit de littéraux de fonction qui font référence à ces variables.

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