Перейти к содержанию

Указатели

TL;DR

  • &x — взять адрес переменной x.
  • *p — разыменовать (получить значение).
  • Передача в функции по значению; для модификации передавай *T.
  • nil-разыменование = runtime panic.

Зачем нужны указатели

  1. Модифицировать аргумент функции.
  2. Не копировать большую структуру.
  3. Optional поля (например, *time.Time для опциональной даты).

Минимальный пример

func double(p *int) {
    *p *= 2
}

x := 5
double(&x)
fmt.Println(x)  // 10

Receiver: pointer vs value

type Counter struct{ n int }

func (c Counter) IncVal()  { c.n++ }   // изменения теряются
func (c *Counter) IncPtr() { c.n++ }   // модифицирует исходный

Правило: используй pointer receiver, если метод меняет state, или если структура большая и копировать дорого.

Гочча — typed nil

type MyError struct{}
func (e *MyError) Error() string { return "" }

func mayFail() error {
    var p *MyError
    return p   // вернёт *MyError(nil), но интерфейс != nil
}

err := mayFail()
fmt.Println(err == nil)  // false

Объяснение: интерфейс хранит (type, value). Тут type = *MyError (≠ nil), value = nil. err == nil true только когда оба = nil.

📖 Подробнее в справочнике задач на 100%.