¿Los mapas se pasan por valor o por referencia en Go?

89

¿Los mapas se pasan por valor o referencia en Go?

Siempre es posible definir una función como sigue, pero ¿es una exageración?

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

Misma pregunta para el valor de retorno. ¿Debo devolver un puntero al mapa o devolver el mapa como valor?

La intención es, por supuesto, evitar la copia de datos innecesaria.

chmike
fuente
4
blog.golang.org/go-maps-in-action : Los tipos de mapas son tipos de referencia, como punteros o cortes, por lo que el valor de m anterior es nulo; no apunta a un mapa inicializado. Un mapa nulo se comporta como un mapa vacío cuando se lee, pero los intentos de escribir en un mapa nulo provocarán un pánico en el tiempo de ejecución; no hagas eso. Para inicializar un mapa, use la función make incorporada
mh-cbon
2
Todo en Go se pasa por valor. Algunos valores resultan ser punteros o estructuras que contienen punteros. (es posible que desee *mapen algunos casos, si necesita reasignar el valor del mapa en una dirección)
JimB
mh-cbon, no hay tipos de referencia en Go.
Inanc Gumus
@ mh-cbon No estaba hablando de un tipo de referencia. Estaba preguntando si un mapa se pasa por referencia, lo que equivale a preguntar si la dirección del mapa se pasa como argumento o una "copia" del mapa (se pasa por valor).
chmike
1
@ mh-cbon Exactamente, los mapas son indicadores de hmap.
Inanc Gumus

Respuestas:

79

En este hilo encontrarás tu respuesta:

Golang: acceder a un mapa usando su referencia

No es necesario utilizar un puntero con un mapa.

Los tipos de mapas son tipos de referencia, como punteros o sectores [1]

Si necesita cambiar la sesión, puede usar un puntero:

map[string]*Session

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

Boris Le Méec
fuente
15
Para evitar errores, tenga en cuenta que los mapas solo se pasan por referencia una vez inicializados , y cuando se reinicializan dentro de una función, la referencia original no se actualizará. Aquí hay un ejemplo ilustrativo del patio de recreo: play.golang.org/p/Q6vrAmmJWR6 O un artículo completo de Dave Cheny dave.cheney.net/2017/04/29/there-is-no-pass-by-reference-in-go
Sindre Myren
18

Aquí hay algunas partes de Si un mapa no es una variable de referencia, ¿qué es? por Dave Cheney:

Un valor de mapa es un puntero a una runtime.hmapestructura.

y conclusión:

Conclusión

Los mapas, como los canales, pero a diferencia de los segmentos, son solo indicadores de tipos de tiempo de ejecución. Como vio arriba, un mapa es solo un puntero a una runtime.hmap estructura.

Los mapas tienen la misma semántica de puntero que cualquier otro valor de puntero en un programa Go. No hay magia salvo la reescritura de la sintaxis del mapa por parte del compilador en llamadas a funciones en formato runtime/hmap.go.

Y algo interesante sobre la historia / explicación de la mapsintaxis:

Si los mapas son indicadores, ¿no deberían serlo *map[key]value?

Es una buena pregunta que si los mapas son valores de puntero, ¿por qué la expresión make(map[int]int)devuelve un valor con el tipo map[int]int? ¿No debería devolver un *map[int]int? Ian Taylor respondió esto recientemente en un golang-tuercas de rosca 1 .

En los primeros días, lo que ahora llamamos mapas se escribían como punteros, así que escribiste *map[int]int. Nos alejamos de eso cuando nos dimos cuenta de que nadie escribía mapsin escribir *map.

Podría decirse que cambiar el nombre del tipo de *map[int]inta map[int]int, aunque confuso porque el tipo no parece un puntero, fue menos confuso que un valor en forma de puntero que no se puede desreferenciar.

Akavall
fuente
1

No. Los mapas son referencia por defecto.

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

    }

Del blog de Golang

Los tipos de mapa son tipos de referencia, como punteros o sectores, por lo que el valor de m anterior es nulo; no apunta a un mapa inicializado. Un mapa nulo se comporta como un mapa vacío cuando se lee, pero los intentos de escribir en un mapa nulo provocarán un pánico en el tiempo de ejecución; no hagas eso. Para inicializar un mapa, use la función make incorporada:

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

Enlace de fragmento de código Juega con él.

alamin
fuente