Указатели
Указатели в Go — операторы `&` и `*`, семантика передачи по значению против ссылки, нулевой указатель и когда указатель действительно нужен.
6 вопросов
JuniorТеорияОчень частоЧто выведет программа?
Что выведет программа?
1 20 30
Открыть задачу →Типичные ошибки
- ✗Ждать
10 20 30: Go передаёт все аргументы по значению, поэтомуn— копияa, и запись в неё оставляетaравным 1. - ✗Ждать
1 20 3: заголовок среза копируется, но копия указывает на тот же массив, поэтомуs[0] = 30видно вmain.
Уточняющие вопросы
- →Почему append к срезу внутри функции иногда не виден снаружи?
- →Чем метод с указательным получателем отличается здесь от метода со значением?
JuniorТеорияЧастоЧто делают операторы & и * с указателями в Go?
Что делают операторы & и * с указателями в Go?
&x берёт адрес x и возвращает указатель типа *T. *p разыменовывает указатель, чтобы прочитать или записать значение, на которое он указывает. Нулевое значение указателя — nil, то есть он пока ни на что не указывает. В Go нет арифметики указателей — нельзя прибавлять или вычитать из указателя так, как позволяет C.
Типичные ошибки
- ✗Путать операторы — думать, что
&разыменовывает, а*берёт адрес - ✗Ожидать, что арифметика указателей в стиле C работает с указателем Go
- ✗Забывать, что нулевое значение указателя —
nil, а не нулевой адрес
Уточняющие вопросы
- →Чем
*Tв типе отличается от*pв выражении? - →Почему Go намеренно не включает арифметику указателей?
JuniorТеорияЧастоЧто выведет программа?
Что выведет программа?
5 1
Открыть задачу →Типичные ошибки
- ✗Ждать, что
xостанется1:p := &xхранит адресx, а не копию, поэтому*p = 5пишет в самx. - ✗Ждать, что
yизменится вслед заx:y := *pкопирует значение1, на котороеpуказывает в этот момент, иyостаётся1.
Уточняющие вопросы
- →Что напечатает программа, если вместо
y := *pнаписатьp = &y? - →Какой тип у
pи почему в нём нельзя хранить адресstring?
JuniorТеорияЧастоЧто произойдёт при сборке и запуске программы?
Что произойдёт при сборке и запуске программы?
Паника: runtime error: invalid memory address or nil pointer dereference
Открыть задачу →Типичные ошибки
- ✗Ждать
0, как при чтении отсутствующего ключаmap:*pчитаетintпо адресу изp, а заnil-указателем нет никакогоint, поэтому программа паникует. - ✗Ждать
<nil>: так напечатал быfmt.Println(p);*pпросит значение за указателем, а не сам указатель.
Уточняющие вопросы
- →Как изменить программу, чтобы она напечатала
0без паники? - →Как функции защититься от переданного ей
nil-указателя?
JuniorТеорияЧастоЧто происходит при разыменовании nil-указателя в Go?
Что происходит при разыменовании nil-указателя в Go?
Разыменование nil-указателя вызывает runtime-панику: invalid memory address or nil pointer dereference. nil — нулевое значение любого указателя, поэтому неприсвоенный указатель хранит nil, пока вы не направите его куда-либо. Защищайтесь через if p != nil перед чтением *p или перехватывайте панику на границе. Тихого чтения нуля, как может дать C, здесь нет.
Типичные ошибки
- ✗Ожидать тихого чтения нулевого значения вместо паники
- ✗Думать, что разыменование nil ловится на этапе компиляции
- ✗Пропускать защиту
if p != nilперед чтением*p
Уточняющие вопросы
- →Как
recoverможет превратить панику nil-указателя в обработанную ошибку? - →Почему nil-указатель конкретного типа может лежать внутри ненулевого интерфейса?
MiddleТеорияЧастоКогда функция должна принимать указатель, а не значение в Go?
Когда функция должна принимать указатель, а не значение в Go?
Берите *T, когда функция должна изменить значение вызывающего или чтобы избежать копирования большой структуры при каждом вызове. Для маленьких неизменяемых данных предпочитайте значение — это держит API безопасным по копии, так что вызываемый не может изменить состояние вызывающего. Передача указателя также позволяет вызываемому видеть nil как «отсутствует», чего параметр-значение выразить не может.
Типичные ошибки
- ✗Брать указатели по умолчанию везде и терять безопасность копии у параметров-значений
- ✗Считать, что параметр-значение может изменить вызывающего без указателя
- ✗Упускать, что только параметр-указатель может нести
nilкак «отсутствует»
Уточняющие вопросы
- →Как этот принцип переносится на выбор получателя метода — значение против указателя?
- →При каком размере структуры стоимость копии начинает реально иметь значение на практике?