W Go wskaźnik to zmienna przechowująca adres innej zmiennej. W przeciwieństwie do niektórych języków, w Go nie można wykonywać arytmetyki wskaźników, co czyni je bezpieczniejszymi. Wskaźniki w Go są często stosowane do:
W Go brakuje wyraźnego wsparcia dla typów referencyjnych, jak na przykład w C++, jednak slices i maps są z natury referencyjne i często przekazuje się je przez wartość.
package main import "fmt" type User struct { Name string } func changeNameByValue(u User) { u.Name = "Wania" } func changeNameByPointer(u *User) { u.Name = "Petja" } func main() { user := User{Name: "Iwan"} changeNameByValue(user) fmt.Println(user.Name) // Iwan changeNameByPointer(&user) fmt.Println(user.Name) // Petja }
Czy wskaźniki mogą wskazywać na stałe lub literały w Go?
Poprawna odpowiedź: Nie, w Go nie można bezpośrednio wziąć adresu ze stałej lub literału. Adres można wziąć tylko ze zmiennej:
x := 5 p := &x // OK p2 := &10 // Błąd kompilacji
Często myli się to z językami, w których coś takiego jest dozwolone.
Historia
Na jednym projekcie programista próbował przekazać wskaźnik na element slajsa, sądząc, że może bezpiecznie modyfikować slajs przez wskaźnik. Popełnił błąd: slajs sam w sobie zawiera wskaźnik, ale po append() adres podstawowej tablicy się zmienia, a zmiany nie zawsze były odzwierciedlane w danych źródłowych. Doprowadziło to do trudnych do zdiagnozowania błędów (dane były "zgubione").
Historia
W projekcie utworzono listę wskaźników na lokalne zmienne w pętli, a po wyjściu z pętli wszystkie wskaźniki wskazywały na tę samą zmienną (zmienną iteracyjną pętli). Błąd zauważono dopiero po awarii w produkcji.
Historia
Programista błędnie założył, że przypisanie wskaźnika zwalnia poprzedni obiekt z pamięci, i jawnie przypisywał wskaźnikowi nil, oczekując natychmiastowego działania GC. W praktyce w Go zbieracz śmieci sam decyduje, kiedy oczyszczać obiekty, ignorując przedwczesne zerowanie odniesień. Doprowadziło to do wycieków tam, gdzie oczekiwano na terminowe zwolnienie pamięci.