Werden Karten in Go als Wert oder als Referenz übergeben?


88

Werden Karten in Go als Wert oder Referenz übergeben?

Es ist immer möglich, eine Funktion wie folgt zu definieren, aber ist dies ein Overkill?

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

Gleiche Frage für Rückgabewert. Soll ich einen Zeiger auf die Karte zurückgeben oder die Karte als Wert zurückgeben?

Es ist natürlich beabsichtigt, unnötige Datenkopien zu vermeiden.


4
blog.golang.org/go-maps-in-action : Kartentypen sind Referenztypen wie Zeiger oder Slices, daher ist der Wert von m oben gleich Null. Es zeigt nicht auf eine initialisierte Karte. Eine Null-Map verhält sich beim Lesen wie eine leere Map, aber Versuche, in eine Null-Map zu schreiben, verursachen eine Laufzeit-Panik. tu das nicht Um eine Karte zu initialisieren, verwenden Sie die eingebaute Funktion make
mh-cbon

2
Alles in Go wird als Wert übergeben. Einige Werte sind Zeiger oder Strukturen, die Zeiger enthalten. ( *mapIn einigen Fällen möchten Sie möglicherweise eine , wenn Sie den Kartenwert an einer Adresse neu
zuweisen müssen.

mh-cbon, es gibt keine Referenztypen in Go.
Inanc Gumus

@ mh-cbon Ich habe nicht über einen Referenztyp gesprochen. Ich wurde gefragt , ob eine Karte übergibt Bezug genommen wird , die , wenn die Adresse der Karte zu fragen , entspricht als Argument oder eine „Kopie“ der Karte (vorbei Wert) übergibt.
Chmike

1
@ mh-cbon Genau, Maps sind Zeiger auf hmap.
Inanc Gumus

Antworten:


78

In diesem Thread finden Sie Ihre Antwort:

Golang: Zugriff auf eine Karte mithilfe ihrer Referenz

Sie müssen keinen Zeiger mit einer Karte verwenden.

Kartentypen sind Referenztypen wie Zeiger oder Slices [1]

Wenn Sie die Sitzung ändern müssen, können Sie einen Zeiger verwenden:

map[string]*Session

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


15
Beachten Sie zur Vermeidung von Pitfals, dass Karten erst nach der Initialisierung als Referenz übergeben werden. Wenn sie innerhalb einer Funktion neu initialisiert werden, wird die ursprüngliche Referenz nicht aktualisiert. Hier ist ein anschauliches Spielplatzbeispiel: play.golang.org/p/Q6vrAmmJWR6 Oder ein vollständiger Artikel von Dave Cheny dave.cheney.net/2017/04/29/there-is-no-pass-by-reference-in-go
Sindre Myren

18

Hier sind einige Teile von Wenn eine Karte keine Referenzvariable ist, welche ist es? von Dave Cheney:

Ein Kartenwert ist ein Zeiger auf eine runtime.hmapStruktur.

und Fazit:

Fazit

Maps sind wie Kanäle, aber im Gegensatz zu Slices, nur Zeiger auf Laufzeittypen. Wie Sie oben gesehen haben, ist eine Karte nur ein Zeiger auf eine runtime.hmap Struktur.

Karten haben dieselbe Zeigersemantik wie alle anderen Zeigerwerte in einem Go-Programm. Es gibt keine Magie außer dem Umschreiben der Kartensyntax durch den Compiler in Aufrufe von Funktionen in runtime/hmap.go.

Und ein interessantes Stück über die Geschichte / Erklärung der mapSyntax:

Wenn Karten Zeiger sind, sollten sie es nicht sein *map[key]value?

Es ist eine gute Frage, warum der Ausdruck make(map[int]int)einen Wert mit dem Typ zurückgibt, wenn Maps Zeigerwerte sind map[int]int. Sollte es nicht ein zurückgeben *map[int]int? Ian Taylor hat dies kürzlich in einem Golang-Nuss- Thread 1 beantwortet .

In den frühen Tagen wurden die sogenannten Karten als Zeiger geschrieben, also haben Sie geschrieben *map[int]int. Wir haben uns davon entfernt, als wir feststellten, dass niemand jemals mapohne Schreiben geschrieben hat *map.

Das Umbenennen des Typs von in *map[int]intin map[int]intwar zwar verwirrend, da der Typ nicht wie ein Zeiger aussieht, aber weniger verwirrend als ein zeigerförmiger Wert, der nicht dereferenziert werden kann.


1

Standardmäßig werden keine Karten referenziert.

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

    }

Vom Golang Blog-

Kartentypen sind Referenztypen wie Zeiger oder Slices. Daher ist der Wert von m oben gleich Null. Es zeigt nicht auf eine initialisierte Karte. Eine Null-Map verhält sich beim Lesen wie eine leere Map, aber Versuche, in eine Null-Map zu schreiben, verursachen eine Laufzeit-Panik. tu das nicht Verwenden Sie zum Initialisieren einer Karte die integrierte Funktion make:

Code Snippet Link Spielen Sie damit.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.