Der häufige Fehler, den ich gefunden habe, ist, dass Leute Zeiger in ihren komplizierten Strukturen vergessen.
Jede Scheibe, Karte, Schnittstelle ist ein Zeiger. Wenn Sie eine Struktur haben, die eine andere Struktur enthält, die einen Zeiger enthält, sehen Sie vielleicht S1{s2: S2}
, und Sie denken, es ist in Ordnung, eine Struktur wie folgt zu kopieren: a=b
, wenn es eigentlich nicht in Ordnung ist, wie in S2, ein poiner vatriable, sagen wir p
, wird ihre Adresse kopiert und nicht der Wert, auf den sie zeigt. Wenn Sie den Wert von * a.s2.p ändern, gibt der * b.s2.p den gleichen Wert zurück.
package main
import (
"fmt"
)
type S1 struct {
v int
s2 S2
}
type S2 struct {
p *int
}
func main() {
x := 1
b := S1{v: 10, s2: S2{p: &x}}
a := b
fmt.Printf("a = %+v\nb = %+v\n*a.s2.p = %d\n*b.s2.p = %d\na.s2.p = %p\nb.s2.p = %p\n", a, b, *a.s2.p, *b.s2.p, a.s2.p, b.s2.p)
*a.s2.p = 5
fmt.Printf("*a.s2.p = %d\n*b.s2.p = %d\na.s2.p = %p\nb.s2.p = %p\n", *a.s2.p, *b.s2.p, a.s2.p, b.s2.p)
}
http://play.golang.org/p/KQ99KICgbu
Dieses es ist ein sehr einfaches Beispiel, und es sieht offensichtlich gibt es ein Problem, aber bei größeren Anwendungen könnte dies nicht so offensichtlich sein.
Dieses Problem tritt auch bei Kanälen auf. Wenn Sie einen Zeiger senden, erhalten Sie am anderen Ende den gleichen Zeiger (eine Kopie des Werts Ihres Zeigers, der eine Adresse ist). In diesem Fall, wie im ersten Fall, besteht eine sichere Lösung darin, eine Clone-Funktion zu verwenden, um ein geklontes Objekt zu erzeugen. Sie senden den Klon über Ihren Kanal und verwenden ihn nicht mehr auf der Senderseite.
Go's noch Müll gesammelt. Die einzige Sache, um die Sie sich wirklich kümmern müssen, ist die korrekte Dereferenzierung in den seltenen Fällen, in denen Sie müssen. Der Compiler prüft dies implizit, weil Sie inkompatible Typen haben, wenn sie falsch sind.Die andere Sache, die dazu tendiert, Leute zu versauen, ist Zeiger-Wert-Empfänger auf Methoden. Wenn Ihr Empfänger ein Wert ist, wird er als Wert an die Methode übergeben. Wenn es ein Zeiger ist, dann wird dies per Referenz getan. Wenn Sie also den Zustand eines Objekts innerhalb einer empfangenen Methode ändern möchten, müssen Sie einen Zeiger verwenden. – evanmcdonnal