В Go указатель представляет собой переменную, хранящую адрес другой переменной. В отличие от некоторых языков, в Go невозможно выполнять арифметику указателей, что делает их безопаснее. Указатели в Go часто применяют для:
В Go отсутствует явная поддержка ссылочных типов, как, например, в C++, однако slices и maps уже являются ссылочными по своей природе, и их часто передают по значению.
package main import "fmt" type User struct { Name string } func changeNameByValue(u User) { u.Name = "Вася" } func changeNameByPointer(u *User) { u.Name = "Петя" } func main() { user := User{Name: "Иван"} changeNameByValue(user) fmt.Println(user.Name) // Иван changeNameByPointer(&user) fmt.Println(user.Name) // Петя }
Могут ли указатели указывать на константы или литералы в Go?
Правильный ответ: Нет, в Go нельзя брать адрес у константы или у литералов напрямую. Адрес можно взять только у переменной:
x := 5 p := &x // OK p2 := &10 // Ошибка компиляции
Это часто путают с языками, где подобное допустимо.
История
На одном проекте разработчик попытался передавать ссылку на элемент слайса, считая, что сможет безопасно модифицировать слайс через указатель. Но ошибся: слайс сам по себе содержит указатель, но после append() адрес подложенного массива меняется, и изменения не всегда отражались на исходных данных. Это привело к трудноуловимым багам (данные "терялись").
История
В проекте был создан список указателей на локальные переменные в цикле, и после выхода из цикла все указатели указывали на одну и ту же переменную (итерируемую переменную цикла). Ошибку заметили только после падения в продакшене.
История
Разработчик ошибочно решил, что присваивание указателя освобождает предыдущий объект из памяти, и явно присваивал указателю nil, ожидая GC сразу. На практике в Go сборщик мусора сам решает, когда чистить объекты, игнорируя преждевременное обнуление ссылок. Это привело к утечкам там, где рассчитывали на своевременное высвобождение памяти.