Le mappe vengono passate per valore o per riferimento in Go?


94

Le mappe vengono passate per valore o riferimento in Go?

È sempre possibile definire una funzione come segue, ma è eccessivo?

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

Stessa domanda per il valore restituito. Devo restituire un puntatore alla mappa o restituire la mappa come valore?

L'intenzione è ovviamente quella di evitare copie di dati non necessarie.


4
blog.golang.org/go-maps-in-action : i tipi di mappa sono tipi di riferimento, come puntatori o sezioni, e quindi il valore di m sopra è nullo; non punta a una mappa inizializzata. Una mappa nulla si comporta come una mappa vuota durante la lettura, ma i tentativi di scrivere su una mappa nulla causeranno un panico durante l'esecuzione; non farlo. Per inizializzare una mappa, usa la funzione make incorporata
mh-cbon

2
Tutto in Go è passato per valore. Alcuni valori sono puntatori o strutture che contengono puntatori. ( *mapin alcuni casi potresti volerne uno , se devi riassegnare il valore della mappa a un indirizzo)
JimB

mh-cbon, non ci sono tipi di riferimento in Go.
Inanc Gumus

@ mh-cbon non stavo parlando di un tipo di riferimento. Chiedevo se una mappa viene passata per riferimento, che equivale a chiedere se l'indirizzo della mappa viene passato come argomento o una "copia" della mappa (passata per valore).
chmike

1
@ mh-cbon Esattamente, le mappe sono puntatori a hmap.
Inanc Gumus

Risposte:


83

In questo thread troverai la tua risposta:

Golang: accedere a una mappa utilizzando il suo riferimento

Non è necessario utilizzare un puntatore con una mappa.

I tipi di mappa sono tipi di riferimento, come puntatori o sezioni [1]

Se hai bisogno di cambiare la sessione puoi usare un puntatore:

map[string]*Session

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


16
Per evitare qualsiasi errore, tieni presente che le mappe vengono passate per riferimento solo una volta inizializzate e quando reinizializzate all'interno di una funzione, il riferimento originale non verrà aggiornato. Ecco un esempio di playground illustrativo: play.golang.org/p/Q6vrAmmJWR6 Oppure un articolo completo di Dave Cheny dave.cheney.net/2017/04/29/there-is-no-pass-by-reference-in-go
Sindre Myren

19

Ecco alcune parti di Se una mappa non è una variabile di riferimento, che cos'è? di Dave Cheney:

Un valore della mappa è un puntatore a una runtime.hmapstruttura.

e conclusione:

Conclusione

Le mappe, come i canali, ma a differenza delle sezioni, sono solo puntatori a tipi di runtime. Come hai visto sopra, una mappa è solo un puntatore a una runtime.hmap struttura.

Le mappe hanno la stessa semantica del puntatore di qualsiasi altro valore del puntatore in un programma Go. Non c'è magia se non la riscrittura della sintassi della mappa da parte del compilatore in chiamate a funzioni in runtime/hmap.go.

E un pezzo interessante sulla storia / spiegazione della mapsintassi:

Se le mappe sono puntatori, non dovrebbero esserlo *map[key]value?

È una buona domanda che se le mappe sono valori puntatore, perché l'espressione make(map[int]int)restituisce un valore con il tipo map[int]int. Non dovrebbe restituire un *map[int]int? Ian Taylor ha risposto di recente in un thread golang-nuts 1 .

Nei primissimi giorni quelle che ora chiamiamo mappe venivano scritte come puntatori, quindi hai scritto *map[int]int. Ci siamo allontanati da questo quando ci siamo resi conto che nessuno ha mai scritto mapsenza scrivere *map.

Probabilmente rinominare il tipo da *map[int]inta map[int]int, sebbene confuso perché il tipo non sembra un puntatore, è stato meno confuso di un valore a forma di puntatore che non può essere dereferenziato.


3

No. Le mappe sono di riferimento per impostazione predefinita.

    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
        // -----------------------

    }

Dal blog Golang-

I tipi di mappa sono tipi di riferimento, come puntatori o sezioni, quindi il valore di m sopra è nullo; non punta a una mappa inizializzata. Una mappa nulla si comporta come una mappa vuota durante la lettura, ma i tentativi di scrivere su una mappa nulla causeranno un panico durante l'esecuzione; non farlo. Per inizializzare una mappa, usa la funzione make incorporata:

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

Link Snippet di codice Gioca con esso.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.