2016-06-03 11 views
4

Ich habe einen map mit komplexen Schlüssel - beispielsweise 2D-Arrays:Kopiert Go (tief) Schlüssel beim Einfügen in eine Karte?

m := make(map[[2][3]int]int) 

Wenn ich einen neuen Schlüssel in die Karte einfügen, geht eine tiefe Kopie des Schlüssels machen?

a := [2][3]int{{1, 2, 3}, {4, 5, 6}} 
m[a] = 1 

Mit anderen Worten, wenn ich das Array a, nachdem es als Kartenschlüssel ändert, wird die Karte immer noch den alten Wert von a enthalten?

+0

Arrays in Go sind Pass-by-Value (im Gegensatz zu Slices, die Pass-by-Referenz sind), so ist dies nicht anders als tun 'a: = 1; m [a] = 1 '; Nachdem die Zuordnungszuweisung ausgeführt wurde, haben der Schlüssel und die Variable keinen Bezug (außer, dass sie immer noch den gleichen Wert haben, wenn Sie nicht einen von ihnen ändern). – joshlf

Antwort

3

Arrays werden immer nach Wert übergeben, also Go in diesem Fall eine tiefe Kopie des Schlüssels.

Vom language spec

Die Vergleichsoperatoren == und = müssen vollständig für die Operanden des Schlüsseltyp definiert werden!; Daher darf der Schlüsseltyp keine Funktion, Map oder Slice sein. Wenn der Schlüsseltyp ein Schnittstellentyp ist, müssen diese Vergleichsoperatoren für die dynamischen Schlüsselwerte definiert werden. Fehler führt zu einer Laufzeitpanik.

Die Schlüssel werden in die Karte kopiert. Ausgenommen map und slice als gültige Schlüssel bedeutet, dass die Schlüssel nicht geändert werden können. Beachten Sie, dass go nicht auf Zeiger folgt, wenn Sie einen Kartentyp mit einem Zeiger als Schlüssel definieren (z. B. map[*int]int), der die Zeiger direkt vergleicht.

+1

Ich würde hier etwas vorsichtiger mit dem Wort "tief" sein: das Einfügen eines Wertes in eine Karte kopiert den * Wert des Schlüssels, * und das ist alles, was dazu gehört. Da jeder Befehl in Go durch Wert übergeben/kopiert wird, wenn wir über Sprachgrundelemente sprechen (Zuweisungsoperator, Übergabe von Argumenten an Funktionen), geschieht dies mit den Werten der Zuordnungsschlüssel.Der Go-Compiler analysiert explizit den Typ, der als Schlüssel jeder Map verwendet wird, um Versuche zu verwerfen, Referenztypen dafür zu verwenden - direkt oder eingebettet in einen Strukturtyp. – kostix

+0

IOW, solches Kopieren ist nicht "tief" oder "seicht"; Es kopiert einen Wert, wie er in der Go-Spezifikation definiert ist. Und da die Map-Keys keine Typen mit Referenzsemantik verwenden können, ist das Kopieren immer "tief" in seinem Ergebnis, aber es ist nicht so, dass es * tief * definiert ist, im Gegensatz zu seicht - es ist nur ein Nebenprodukt von wie Werte in Go übergeben/kopiert werden ;-) – kostix

6

Kurze Antwort, es wird kopiert.

Nach Spezifikation sind Arrays value types.

Go's Arrays sind Werte. Eine Array-Variable bezeichnet das gesamte Array; es ist kein Zeiger auf das erste Array-Element (wie es in C der Fall wäre). Das heißt, wenn Sie einen Array-Wert zuweisen oder übergeben, erstellen Sie eine Kopie seines Inhalts. (. Um die Kopie zu vermeiden Sie einen Zeiger auf das Array übergeben werden können, aber dann ist das ein Zeiger auf ein Array, kein Array) https://blog.golang.org/go-slices-usage-and-internals

überzeugen Sie sich selbst:

https://play.golang.org/p/fEUYWwN-pm

package main 

import (
    "fmt" 
) 

func main() { 
    m := make(map[[2][3]int]int) 
    a := [2][3]int{{1, 2, 3}, {4, 5, 6}} 

    fmt.Printf("Pointer to a: %p\n", &a) 

    m[a] = 1 
    for k, _ := range m { 
     fmt.Printf("Pointer to k: %p\n", &k) 
    } 
} 

Die Zeiger stimmen nicht überein.

EDIT: Der wahre Grund ist, wenn Sie in eine Karte einfügen, wird der Schlüsselwert kopiert. Oder Sie können sich weiterhin nur an die obige Regel erinnern: Arrays sind Werttypen und ihre Wiederverwendung bezeichnet eine Kopie. Entweder funktioniert hier. :)

Verwandte Themen