Die Strukturen map und slice in Go haben wichtige Besonderheiten in Bezug auf das Kopieren und die Semantik der Arbeit mit dem Speicher, die häufig zu unerwartetem Verhalten bei unerfahrenen Entwicklern führen.
Obwohl Go als strikter Typ mit statischer Typisierung gilt und es standardmäßig keine Zeiger gibt, verfügen map und slice über ein spezielles internes Modell: Beide Typen sind Referenzstrukturen. Genau das legt Einschränkungen fest und schafft viele Nuancen beim Kopieren und Übertragen dieser Objekte.
Die Kopie von map und slice führt nicht zu einer tiefen Kopie des Inhalts, sondern bildet einen neuen Verweis auf dasselbe Objekt, was zu unerwarteten Nebenwirkungen beim Ändern von Daten, falschen Rückgaben von Werten aus Funktionen und Modifikationen führt. Darüber hinaus kann die Rückgabe von map oder slice als Ergebnis einer Funktion zusätzliche Allokationen oder Lecks hervorrufen.
b := a[:]). Für das vollständige Kopieren der Elemente muss die eingebaute Funktion copy() verwendet werden.Beispiel für korrektes Kopieren:
// Kopieren des Slices a := []int{1, 2, 3} b := make([]int, len(a)) copy(b, a) // b ist jetzt unabhängig von a // Kopieren von map src := map[string]int{"x": 1} dst := make(map[string]int) for k, v := range src { dst[k] = v }
Wichtige Merkmale:
slice und map sind Referenztypen, werden über den Deskriptor kopiert und nicht über den InhaltWas passiert, wenn man einfach einen map/slice einem anderen zuweist und dann einen von ihnen ändert?
Sowohl map als auch slice zeigen auf dieselben Daten im Speicher: Änderungen beeinflussen beide Objekte.
Warum wird oft gesagt, dass die Rückgabe eines slice oder map aus einer Funktion "speichereffizient" ist?
Weil eine Kopie des Deskriptors zurückgegeben wird, nicht des gesamten Inhalts. Die Daten im Heap leben so lange, wie es Referenzen darauf gibt.
Kann man mit der Funktion copy() eine "tiefe" Kopie von map erstellen?
Nein, copy() funktioniert nur mit Slices und Arrays, für maps ist immer eine Schleife erforderlich.
Ein Entwickler kopiert einen Slice oder map durch Zuweisung und ändert die Kopie zum Schutz vor Nebenwirkungen:
Vorteile:
Nachteile:
Vor der Modifikation erforderlicher Daten wird copy() für den Slice und eine Schleife für die map verwendet:
Vorteile:
Nachteile: