← Назад к вопросам

Как работает указатель?

1.3 Junior🔥 251 комментариев
#Основы Go

Комментарии (1)

🐱
gpt-5-nanoPrepBro AI4 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое указатель и зачем он нужен

Указатель в Go — это переменная, которая хранит адрес другой переменной. Он позволяет разделить владение и изменение данных, избегать лишнего копирования больших структур и реализовывать эффективное взаимодействие между функциями. В Go указатели не поддерживают арифметику адресов, как в C; это упрощает безопасность и уменьшает риски ошибок. Основные операции с указателями: получение адреса переменной с помощью оператора & и разыменование через оператор *.

  • Адрес переменной: через &var получаем указатель на переменную.
  • Разыменование: через *ptr получаем саму переменную и можем её изменять.
  • Nil-указатель: нулевой указатель имеет значение nil и не указывает ни на что.

Как работает указатель на примере

package main

import "fmt"

func main() {
    x := 10          // обычная переменная
    p := &x          // указатель на x
    fmt.Println(*p)  // разыменование: 10

    *p = 20            // изменение через указатель
    fmt.Println(x)     // x теперь 20
}
  • В этом примере изменение через разыменование влияет на исходную переменную x.
  • Go позволяет обращаться к полям структур через указатель без явного разыменования: p.Field эквивалентно (*p).Field.

Важные особенности и ограничения

  • Nil указывает на отсутствие значения: проверяйте if p == nil прежде чем разыменовывать.
  • Передача по ссылке: передача указателя в функцию позволяет модифицировать аргумент без копирования всей структуры.
  • Нет арифметики указателей: нельзя выполнять операции вроде ptr++ или вычислять адреса произвольных элементов как в C. Можно работать только с конкретными адресами или с элементами в контейнерах.
  • Чтение и запись через указатель: можно как читать, так и писать через разыменование.
package main

import "fmt"

func inc(n *int) {
    *n = *n + 1
}

func main() {
    v := 5
    inc(&v)
    fmt.Println(v) // 6
}

Где это применимо на практике

  • Передача большого объекта в функцию без копирования.
  • Модификация значения внутри функции.
  • Связанные структуры данных, где нужно ссылаться на одни и те же данные.
  • Оптимизация и контроль над временем жизни данных (с небольшими оговорками по escape-анализу компилятора).

Безопасность и глубже: экраны и unsafe

  • Go имеет сборщик мусора; указатели позволяют безопасно совместно использовать данные, но избыточное использование указателей может приводить к «escape» переменных в куче, что влияет на производительность.
  • В крайних случаях можно обратиться к указателю через пакет unsafe для низкоуровневых манипуляций, но это разрушает большинство гарантий безопасности и может повлиять на сборку мусора и совместимость с GC.
package main

import (
    "fmt"
    "unsafe"
)

func main() {
    i := 42
    p := unsafe.Pointer(&i)
    q := (*int)(p)
    *q = 100
    fmt.Println(i) // 100
}

Заключение: указатели в Go дают мощный инструмент для эффективной работы с данными и модификации аргументов функций, но требуют дисциплины: избегайте лишних разыменований и помните про nil и безопасность параллелизма.

Как работает указатель? | PrepBro