Czy mapy są przekazywane według wartości czy przez odniesienie w Go?

89

Czy mapy są przekazywane według wartości lub odniesienia w Go?

Zawsze można zdefiniować funkcję następującą, ale czy to przesada?

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

To samo pytanie dla wartości zwracanej. Czy powinienem zwrócić wskaźnik do mapy, czy też zwrócić mapę jako wartość?

Celem jest oczywiście uniknięcie niepotrzebnego kopiowania danych.

chmike
źródło
4
blog.golang.org/go-maps-in-action : typy map są typami referencyjnymi, takimi jak wskaźniki lub plasterki, więc wartość m powyżej wynosi zero; nie wskazuje na zainicjowaną mapę. Mapa zerowa zachowuje się jak pusta mapa podczas czytania, ale próby zapisu do mapy zerowej spowodują panikę w czasie wykonywania; nie rób tego. Aby zainicjować mapę, użyj wbudowanej funkcji make
mh-cbon
2
Wszystko w Go jest przekazywane przez wartość. Niektóre wartości są wskaźnikami lub strukturami zawierającymi wskaźniki. (możesz chcieć *mapw niektórych przypadkach, jeśli chcesz ponownie przypisać wartość mapy pod adresem)
JimB
mh-cbon, w Go nie ma typów odwołań.
Inanc Gumus
@ mh-cbon Nie mówiłem o typie referencyjnym. Pytałem, czy mapa jest przekazywana przez odniesienie, co jest równoznaczne z zapytaniem, czy adres mapy jest przekazywany jako argument, czy „kopia” mapy (przekazywana przez wartość).
chmike
1
@ mh-cbon Dokładnie, mapy są wskaźnikami do hmap.
Inanc Gumus

Odpowiedzi:

79

W tym wątku znajdziesz swoją odpowiedź:

Golang: Dostęp do mapy przy użyciu jej odniesienia

Nie musisz używać wskaźnika z mapą.

Typy map to typy odwołań, takie jak wskaźniki lub wycinki [1]

Jeśli potrzebujesz zmienić sesję, możesz użyć wskaźnika:

map[string]*Session

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

Boris Le Méec
źródło
15
Aby uniknąć pułapek, należy pamiętać, że mapy są przekazywane przez odniesienie tylko po zainicjowaniu , a po ponownym zainicjowaniu wewnątrz funkcji oryginalne odniesienie nie zostanie zaktualizowane. Oto przykładowy przykład placu zabaw: play.golang.org/p/Q6vrAmmJWR6 Lub pełny artykuł autorstwa Dave'a Cheny'ego dave.cheney.net/2017/04/29/there-is-no-pass-by-reference-in-go
Sindre Myren
18

Oto kilka części z Jeśli mapa nie jest zmienną odniesienia, co to jest? przez Dave Cheney:

Wartość mapy jest wskaźnikiem do runtime.hmapstruktury.

i wniosek:

Wniosek

Mapy, podobnie jak kanały, ale w przeciwieństwie do wycinków, są tylko wskaźnikami do typów środowiska wykonawczego. Jak widzieliście powyżej, mapa jest tylko wskaźnikiem do runtime.hmap struktury.

Mapy mają taką samą semantykę wskaźnika, jak każda inna wartość wskaźnika w programie Go. Nie ma magii, poza przepisywaniem składni mapy przez kompilator na wywołania funkcji w programie runtime/hmap.go.

I ciekawostka o historii / wyjaśnieniu mapskładni:

Jeśli mapy są wskaźnikami, czyż nie *map[key]value?

To dobre pytanie, jeśli mapy są wartościami wskaźnika, dlaczego wyrażenie make(map[int]int)zwraca wartość z typem map[int]int. Czy nie powinien zwrócić *map[int]int? Ian Taylor odpowiedział niedawno w golang orzechów wątku 1 .

Na samym początku to, co teraz nazywamy mapami, było pisane jako wskaźniki, więc napisałeś *map[int]int. Odeszliśmy od tego, gdy zdaliśmy sobie sprawę, że nikt nigdy nie pisał mapbez pisania *map.

Prawdopodobnie zmiana nazwy typu z *map[int]intna map[int]int, choć myląca, ponieważ typ nie wygląda jak wskaźnik, była mniej myląca niż wartość w kształcie wskaźnika, której nie można wyłuskać.

Akavall
źródło
1

Nie. Mapy są domyślnie odniesieniami.

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

    }

Z bloga Golang-

Typy map są typami referencyjnymi, takimi jak wskaźniki lub wycinki, więc wartość m powyżej wynosi zero; nie wskazuje na zainicjowaną mapę. Mapa zerowa zachowuje się jak pusta mapa podczas czytania, ale próby zapisu do mapy zerowej spowodują panikę w czasie wykonywania; nie rób tego. Aby zainicjalizować mapę, użyj wbudowanej funkcji make:

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

Link do fragmentu kodu Graj z tym.

alamin
źródło