Об указателях в C/C++ рассказывают страшные истории. Однако указатели в Go очень просты и удобны: два использования оператора звездочки, одно использование оператора амперсанда, и все готово.

Давайте посмотрим на них в истории жизни переменных a, b, c и d.

  1. a 42 года, «Ответ на главный вопрос жизни, Вселенной и всего остального»
a := 42

2. b также хотел бы поделиться драгоценной ценностью с a

b := a

3. Затем есть c, который хочет хранить не целочисленное значение, а адрес целочисленной переменной

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

var c *int

Использование оператора амперсанда:если он ставится перед переменной, он возвращает адрес этой переменной.

c = &a

4. Теперь у нас есть черный ход для доступа к a

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

*c // This basically gives us the variable a

5. Изменение значения b не влияет на a , поскольку единственная связь b с a заключается в том, что он просто скопировал его значение один раз.

b = 43 // variable a still has the value 42

6. Однако, поскольку c знает, где aживет, с c мы можем делать все, что захотим a

*c = 44 // now variable a's value is set to 44, no longer the answer to the ultimate question... 

7. Более того, пусть переменная d скопирует значение c, чтобы у нас было две переменные *int, которые знают, где живет a

d := c

8. Теперь с *d у нас также есть полный контроль над (бедными) a

*d = 45 // now both a and *c give back 45

Указатели Go сами по себе являются переменными. Два указателя, указывающих на один и тот же адрес (например, c и d ), по-прежнему полностью независимы, каждый занимает свой собственный адрес в памяти. Самая запутанная ситуация C++, когда одна и та же память представлена ​​несколькими псевдонимами или ссылками на переменные, в Go не произойдет.

Другая заманчивая идея заключается в том, могут ли указатели на разные типы присваиваться друг другу, поскольку все они хранят адреса памяти. Ответ «нет», даже для базовых типов:

type i int
var a i
a = 1
var b *int
b = &a // You can't do this!