Go - Указатели

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

Как вы знаете, каждая переменная является местом памяти, и каждая ячейка памяти имеет свой адрес, который можно получить, используя оператор ampersand (&), который обозначает адрес в памяти. Рассмотрим следующий пример, который будет печатать адрес определяемых переменных:

package main

import "fmt"

func main() {
   var a int = 10   
   fmt.Printf("Address of a variable: %x\n", &a  )
}

Что такое указатели?

Указатель является переменной, значение которого является адрес другой переменной, т.е. прямой адрес ячейки памяти. Как и любая переменная или константа, вы должны объявить указатель, прежде чем сможете использовать его для хранения любого адреса переменной. Общая форма объявления переменной указателя:

var var_name *var-type

Здесь тип - это базовый тип указателя; он должен быть допустимым типом данных C, а имя-var - имя переменной-указателя. Звездочка *, которую вы использовали для объявления указателя, представляет собой ту же звездочку, которую вы используете для умножения. Однако в этом утверждении звездочка используется для обозначения переменной как указателя. Ниже приведена действительная декларация указателя:

var ip *int        /* pointer to an integer */
var fp *float32    /* pointer to a float */

Фактический тип данных для всех указателей, будь то integer, float или other, является тем же самым, длинным шестнадцатеричным числом, которое представляет адрес памяти. Единственное различие между указателями разных типов данных - это тип данных переменной или константы, на которые указывает указатель.

Как использовать указатели?

Существует несколько важных операций, которые мы часто выполняем с указателями: (a) мы определяем переменные указателя, (b) присваиваем адрес переменной указателю и (c) получаем доступ к значению по адресу, хранящемуся в переменной указателя ,

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

package main

import "fmt"

func main() {
   var a int = 20   /* actual variable declaration */
   var ip *int      /* pointer variable declaration */

   ip = &a  /* store address of a in pointer variable*/

   fmt.Printf("Address of a variable: %x\n", &a  )

   /* address stored in pointer variable */
   fmt.Printf("Address stored in ip variable: %x\n", ip )

   /* access the value using the pointer */
   fmt.Printf("Value of *ip variable: %d\n", *ip )
}

Нильские указатели в Go

Go компилятор присваивает значение Nil переменной-указателю в случае, если у вас нет точного адреса для назначения. Это делается во время объявления переменной. Указатель, которому назначено nil, называется указателем nil .

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

package main

import "fmt"

func main() {
   var  ptr *int

   fmt.Printf("The value of ptr is : %x\n", ptr  )
}

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

The value of ptr is 0

В большинстве операционных систем программам не разрешается обращаться к памяти по адресу 0, поскольку эта память зарезервирована операционной системой. Однако адрес памяти 0 имеет особое значение; он сигнализирует, что указатель не предназначен для указания на доступную ячейку памяти. Но по соглашению, если указатель содержит значение nil (ноль), предполагается, что он ничего не указывает.

Чтобы проверить нулевой указатель, вы можете использовать оператор if следующим образом:

if(ptr != nil)     /* succeeds if p is not nil */
if(ptr == nil)    /* succeeds if p is null */