Les cartes sont-elles transmises par valeur ou par référence dans Go?

89

Les cartes sont-elles transmises par valeur ou référence dans Go?

Il est toujours possible de définir une fonction comme suit, mais est-ce exagéré?

func foo(dat *map[string]interface{}) {...}

Même question pour la valeur de retour. Dois-je renvoyer un pointeur vers la carte ou renvoyer la carte comme valeur?

L'intention est bien entendu d'éviter la copie inutile de données.

chmike
la source
4
blog.golang.org/go-maps-in-action : Les types de carte sont des types de référence, comme des pointeurs ou des tranches, et donc la valeur de m ci-dessus est nulle; il ne pointe pas vers une carte initialisée. Une map nil se comporte comme une map vide lors de la lecture, mais les tentatives d'écriture sur une map nil provoqueront une panique à l'exécution; ne fais pas ça. Pour initialiser une carte, utilisez la fonction make intégrée
mh-cbon
2
Tout dans Go est passé par valeur. Certaines valeurs sont des pointeurs ou des structures contenant des pointeurs. (vous voudrez peut-être un *mapdans certains cas, si vous devez réaffecter la valeur de la carte à une adresse)
JimB
mh-cbon, il n'y a pas de types de référence dans Go.
Inanc Gumus
@ mh-cbon Je ne parlais pas d'un type de référence. Je demandais si une carte est passée par référence, ce qui équivaut à demander si l'adresse de la carte est passée en argument ou en "copie" de la carte (passée par valeur).
chmike
1
@ mh-cbon Exactement, les cartes sont des pointeurs vers hmap.
Inanc Gumus

Réponses:

79

Dans ce fil, vous trouverez votre réponse:

Golang: accéder à une carte en utilisant sa référence

Vous n'avez pas besoin d'utiliser un pointeur avec une carte.

Les types de carte sont des types de référence, comme des pointeurs ou des tranches [1]

Si vous avez besoin de changer de session, vous pouvez utiliser un pointeur:

map[string]*Session

https://blog.golang.org/go-maps-in-action

Boris Le Méec
la source
15
Pour éviter tout pitfals, sachez que les cartes ne sont passées par référence qu'une fois initialisées , et lorsqu'elles sont réinitialisées à l'intérieur d'une fonction, la référence d' origine ne sera pas mise à jour. Voici un exemple de terrain de jeu illustratif: play.golang.org/p/Q6vrAmmJWR6 Ou un article complet de Dave Cheny dave.cheney.net/2017/04/29/there-is-no-pass-by-reference-in-go
Sindre Myren
18

Voici quelques parties de Si une carte n'est pas une variable de référence, qu'est-ce que c'est? par Dave Cheney:

Une valeur de carte est un pointeur vers une runtime.hmapstructure.

et conclusion:

Conclusion

Les cartes, comme les canaux, mais contrairement aux tranches, ne sont que des pointeurs vers des types d'exécution. Comme vous l'avez vu ci-dessus, une carte n'est qu'un pointeur vers une runtime.hmap structure.

Les cartes ont la même sémantique de pointeur que toute autre valeur de pointeur dans un programme Go. Il n'y a pas de magie sauf la réécriture de la syntaxe de la carte par le compilateur en appels aux fonctions dans runtime/hmap.go.

Et un peu intéressant sur l'histoire / l'explication de la mapsyntaxe:

Si les cartes sont des pointeurs, ne devraient-elles pas l'être *map[key]value?

C'est une bonne question que si les cartes sont des valeurs de pointeur, pourquoi l'expression make(map[int]int)renvoie-t-elle une valeur avec le type map[int]int. Ne devrait-il pas renvoyer un *map[int]int? Ian Taylor a répondu à cela récemment dans un fil de discussion 1 .

Au tout début, ce que nous appelons maintenant les cartes étaient écrites sous forme de pointeurs, vous avez donc écrit *map[int]int. Nous nous sommes éloignés de cela lorsque nous avons réalisé que personne n'écrivait mapsans écrire *map.

On peut soutenir que renommer le type de *map[int]intà map[int]int, tout en déroutant parce que le type ne ressemble pas à un pointeur, était moins déroutant qu'une valeur en forme de pointeur qui ne peut pas être déréférencée.

Akavall
la source
1

Non. Les cartes sont des références par défaut.

    package main

    import "fmt"

    func mapToAnotherFunction(m map[string]int) {
        m["hello"] = 3
        m["world"] = 4
        m["new_word"] = 5
    }

    // func mapToAnotherFunctionAsRef(m *map[string]int) {
    // m["hello"] = 30
    // m["world"] = 40
    // m["2ndFunction"] = 5
    // }

    func main() {
        m := make(map[string]int)
        m["hello"] = 1
        m["world"] = 2

        // Initial State
        for key, val := range m {
            fmt.Println(key, "=>", val)
        }

        fmt.Println("-----------------------")

        mapToAnotherFunction(m)
        // After Passing to the function as a pointer
        for key, val := range m {
            fmt.Println(key, "=>", val)
        }

        // Try Un Commenting This Line
        fmt.Println("-----------------------")

        // mapToAnotherFunctionAsRef(&m)
        // // After Passing to the function as a pointer
        // for key, val := range m {
        //  fmt.Println(key, "=>", val)
        // }

        // Outputs
        // hello => 1
        // world => 2
        // -----------------------
        // hello => 3
        // world => 4
        // new_word => 5
        // -----------------------

    }

Du blog Golang-

Les types de carte sont des types de référence, comme des pointeurs ou des tranches, et donc la valeur de m ci-dessus est nulle; il ne pointe pas vers une carte initialisée. Une map nil se comporte comme une map vide lors de la lecture, mais les tentatives d'écriture sur une map nil provoqueront une panique à l'exécution; ne fais pas ça. Pour initialiser une carte, utilisez la fonction make intégrée:

// Ex of make function
m = make(map[string]int)

Code Snippet Link Jouez avec.

Alamin
la source