Учебник по указателям в golang

В компьютере есть два важных компонента: ЦП и память. ЦП в основном отвечает за вычисления, а память отвечает за хранение. В коде, который мы пишем, определенные переменные будут помещены в память во время выполнения. Разные переменные имеют разную длину, а также разные блоки и размеры, занимаемые в памяти.

Вероятно, как показано на рисунке ниже, конечно, реальный вид не такой, здесь просто пример.

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

Помните: каждая переменная имеет адрес, и значением указателя является адрес.

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

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

В Golang есть три основных концепции указателей:

  • адрес указателя
  • тип указателя
  • значение указателя

Адрес и тип указателя

Переменная-указатель может указывать на адрес памяти любого значения, а объем памяти, занимаемый переменной-указателем, является фиксированным значением, независимо от размера значения, на которое она указывает. На 32-битной машине переменная-указатель занимает 4 байта, а на 64-битной — 8 байт. Когда переменная-указатель определена и не назначена какой-либо переменной, ее значение по умолчанию равно nil.

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

Предположим, что тип переменной pесть T, где pпредставляет собой переменную, адрес которой берется, а результат получает addr, то есть адрес переменной pприсваивается переменной addr, тип addr равен *t.

Результат выглядит следующим образом:

0xc00010c008 => *int

Значение указателя

После того, как мы получим указатель переменной с помощью оператора &, мы можем использовать оператор * для получения значения указателя.

Результат выглядит следующим образом:

addr type: *int
the address of pointer: 0xc0000b2008
value type: int
value: 1

Оператор адреса & и оператор значения * представляют собой пару дополнительных операторов, &принимает адрес, а *принимает значение, на которое указывает адрес, в соответствии с адресом.

Отношения и характеристики переменных, адресов указателей, переменных указателей, адресов и значений следующие:

  • Используйте &operator, чтобы взять адрес переменной, вы можете получить переменную-указатель этой переменной.
  • Значением переменной-указателя является адрес указателя.
  • Используйте *operator для получения значения исходной переменной, на которую указывает переменная-указатель.

Исключение нулевого указателя

После выполнения приведенного выше кода будет сообщено об ошибке:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x1054ca2]

Чтобы работать с переменной-указателем, это должен быть указанный адрес. Хотя мы объявили переменную fooвыше, но не присвоили ей адрес памяти, поэтому во время выполнения будет сообщено об исключении нулевого указателя. Обычно мы оптимизируем его до foo := new(int).

Перестановка нулевого указателя

Как вы думаете, в приведенном выше коде значения переменных foo и bar будут заменены? Результат будет:

1 2

Это означает, что между ними нет обмена. При выполнении функции swap было объявлено 4 переменные, как показано ниже:

Следует отметить, что &fooи &barгенерируют новые переменные, когда значение передается в функцию swap, и имеют новый адрес в памяти, но значение, которое они хранят в памяти, является адресом.

После свопинга &fooуказывает на блок памяти 0x004, соответствующее значение 0x002, &barуказывает на блок памяти 0x003, соответствующее значение 0x001, они делают своп, но для адресных блоков 0x001и 0x002 они не изменились, поэтому окончательный результат печати не изменился.

Примечания по использованию указателей

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

Но есть несколько моментов, о которых следует помнить при его использовании:

  • Старайтесь не использовать указатели для ссылочных типов, таких как channel .
  • Нет необходимости использовать указатели для простых данных, таких как int и bool.
  • Лучше не вкладывать указатели, а не один указатель в другой указатель.
  • Сценарии, требующие безопасности параллелизма, бесполезные указатели

Спасибо, что прочитали эту статью. Если вы считаете, что статья написана хорошо, подписывайтесь на меня.

Если вы найдете какие-либо ошибки в этой статье, пожалуйста, оставьте сообщение для обсуждения.

Хорошего дня.