Найти тему

#13 Работа с указателями в Go

Оглавление

Для работы с указателями существует два оператора — амперсанд & и звёздочка *.

Если перед именем переменной стоит амперсанд, значит мы хотим получить адрес этой переменной. Звездочка - это оператор разыменовывания.

В примере указатель ptr не содержит значение переменной p типа int, а содержит только ее адрес.

Адрес в памяти представляет собой шестнадцатеричное число, например, 0x1400009c018. Каждая программа при запуске создается в собственном пространстве памяти, указатель будет разным при каждом запуске, поэтому, если вы запустите код из примера, то адрес у вас будет другим.

Изменение значения по указателю

-2

Переменная ptr указывает на адрес переменной str. Это означает, что если мы изменим значение, на которое указывает переменная ptr, мы также изменим значение переменной str.

В конце мы установили для переменной-указателя ptr значение nil, тем самым освободим область памяти, выделенную под переменную ptr. Значение переменной str не изменилось.

Передача по значению и по ссылке

В Go все аргументы функций по умолчанию передаются по значению. Передается копия значения и любые изменения аргумента в этой функции влияют только на эту функцию, но не на источник.

Если передавать аргумент в функцию по ссылке, то можно изменить значение внутри функции и тем самым изменить значение исходной переменной, которая была передана.

-3

Если надо, чтобы функция, куда вы передаете переменную, могла изменять эту переменную, вы должны передавать ее как указатель.

Нулевое значение и функция new

Для указателей нулевым значением является nil, что означает, что указатель не указывает ни на какой объект в памяти.

Еще один способ объявления указателей использования функции new. Она используется для выделения памяти для переменной и возвращает указатель на эту переменную. Указатель, возвращаемый функцией new, указывает на нулевое значение типа, для которого была выделена память.

-4

Хорошей практикой является проверка аргумента указателя на равенство nil. Это защитит программу от генерации паники.

Ресиверы (приемники) методов, как указатели

В Go, методы могут быть связаны как со значениями структур, так и с указателями на структуры. Это определяет, как метод будет получать доступ к экземпляру структуры и какие операции он сможет выполнять.

Методы с приемниками-значениями

Когда метод имеет приемник-значение, он работает с копией. Изменения, вносимые в поля структуры внутри метода, не затрагивают оригинальную структуру.

-5

Метод Scale имеет приемник-значение, поэтому, когда он вызывается, используется копия v, и изменения в Scale не влияют на исходное значение v.

Методы с приемниками-указателями

Если метод имеет приемник-указатель, он может изменять поля структуры, на которую указывает приемник, поскольку имеет прямой доступ к этой памяти.

-6

В этом примере метод Scale имеет приемник-указатель, и изменения, которые он вносит в v, влияют на оригинальный экземпляр структуры, так как v фактически указывает на место в памяти, где хранится Vertex.

Примечание по синтаксису

Можно вызвать метод с приемником-указателем на значение, и компилятор автоматически возьмет адрес этого значения.

-7

Такое поведение очень удобно, поскольку позволяет избегать явного разыменования или получения адреса значения при вызове методов.

Арифметика указателей

В Go, в отличие от других языков, таких как C++, арифметика указателей не поддерживается напрямую. К примеру, нельзя прибавить или вычесть числа непосредственно у указателя, перемещая его вдоль блока памяти.

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

Если нужно выполнить операции, похожие на арифметику указателей, то можно попробовать реализовать подобное на слайсах:

-8