# Базовые вопросы по Golang

### Характеристики Go <a href="#docs-internal-guid-b2a3515b-7fff-4d9f-932f-5c7a12c697db" id="docs-internal-guid-b2a3515b-7fff-4d9f-932f-5c7a12c697db"></a>

* Императивный&#x20;

&#x20;   Императивное программирование — это парадигма, основанная на составлении алгоритма действий (инструкций/команд), которые изменяют состояние (информацию/данные/память) программы.

&#x20;   Декларативное программирование — это парадигма, при которой описывается желаемый результат, без составления детального алгоритма его получения. В пример можно привести HTML и SQL. <br>

* Компилируемый в нативный код
* Статическая типизация\
  Стати́ческая типиза́ция — приём, широко используемый в языках программирования, при котором переменная, параметр подпрограммы, возвращаемое значение функции связывается с типом в момент объявления и тип не может быть изменён позже.
* Нет классов, но есть структуры с методами
* Есть интерфейсы
* Нет наследования, но есть встраивание
* Функции - объекты первого класса. Функции первого класса - это означает, что язык поддерживает передачу функций в качестве аргументов другим функциям, возврат их как результат других функций, присваивание их переменным или сохранение в структурах данных
* Есть замыкания\
  Замыкание - это функция, которая ссылается к переменным вне ее тела. Функция имеет доступ к связанным переменным, а также может присваивать им значения; в этом смысле функция "связана" с этими переменными.
* Функции могут возвращать больше 1 значения
* Есть указатели, но нет адресной арифметики
* Обширные возможности для конкурентности
* Сборка в 1 бинарный файл
* Набор стандартный инструментов

### Какие технологические преимущества экосистемы Go вы можете назвать?

#### Прекрасная стандартная библиотека <a href="#anchor4anchorprekrasnaya-standartnaya-biblioteka" id="anchor4anchorprekrasnaya-standartnaya-biblioteka"></a>

[Стандартная библиотека](https://golang.org/pkg/) Go действительно великолепна, особенно применительно к разработке сетевых протоколов или API: в ней есть HTTP-клиент и сервер, шифрование, форматы архивирования, сжатие, отправка писем и так далее. Есть даже парсер HTML и довольно мощный движок шаблонов, что позволяет создавать текст и HTML с автоматическим экранированием (automatic escaping) для защиты от XSS (к примеру, используется в [Hugo](https://gohugo.io/templates/introduction/)).

### Чем вам нравится golang?

* Простой, надежный и продуктивный.
* Открытый исходный код.
* Быстрая компиляция и выполнение.
* Простое управление зависимостями.
* Качественно составленные полезные пакеты stdlib.
* Простая обработка ошибок.
* Один бинарный файл для управления всеми другими.
* Кросс-компиляция.
* Сборка мусора.
* Читабельность.
* Встроенное тестирование.
* Профилирование.

### Статическая или динамическая типизация? строготипизирован или нет

Go — язык со строгой [статической типизацией](https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B0%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D1%82%D0%B8%D0%BF%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F). Доступен автоматический вывод типов. Для пользовательских типов используется «[утиная типизация](https://ru.wikipedia.org/wiki/%D0%A3%D1%82%D0%B8%D0%BD%D0%B0%D1%8F_%D1%82%D0%B8%D0%BF%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F)».&#x20;

В [1974 году](https://ru.wikipedia.org/wiki/1974_%D0%B3%D0%BE%D0%B4) [Лисков](https://ru.wikipedia.org/wiki/%D0%9B%D0%B8%D1%81%D0%BA%D0%BE%D0%B2,_%D0%91%D0%B0%D1%80%D0%B1%D0%B0%D1%80%D0%B0) и Зиллес ([англ.](https://ru.wikipedia.org/wiki/%D0%90%D0%BD%D0%B3%D0%BB%D0%B8%D0%B9%D1%81%D0%BA%D0%B8%D0%B9_%D1%8F%D0%B7%D1%8B%D0%BA) Liskov and Zilles) назвали сильно типизированными те языки, в которых «при передаче объекта из вызывающей функции в вызываемую тип этого объекта должен быть совместим с типом, определённым в вызываемой функции»[\[3\]](https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D0%B8_%D1%81%D0%BB%D0%B0%D0%B1%D0%B0%D1%8F_%D1%82%D0%B8%D0%BF%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F#cite_note-3).

### Что вас огорчает в системе типов Go?

* **Отсутствие перечислимых типов.** Вместо них используются группы констант, но все константы-значения фактически являются целыми числами, группы эти синтаксически не объединены, и компилятор не может контролировать их использование. Невозможно описать тип, связанный с перечислением, например, массив, содержащий по одному элементу на каждый элемент перечисления (который в Паскале описывается конструкцией вида `type EnumArray = array[EnumType] of ElementType`), создать цикл по перечислению, компилятор не может контролировать полноту списка альтернатив в конструкции `switch`, когда в качестве селектора используется значение перечисления.
* **Недостаточность встроенных контейнерных типов данных.**\
  Встроенные в язык контейнеры ограничиваются массивами и отображениями, а контейнеры, реализуемые средствами самого языка (в том числе входящие в стандартную библиотеку), [нетипобезопасны](https://ru.wikipedia.org/wiki/%D0%A2%D0%B8%D0%BF%D0%BE%D0%B1%D0%B5%D0%B7%D0%BE%D0%BF%D0%B0%D1%81%D0%BD%D0%BE%D1%81%D1%82%D1%8C) из-за вынужденного использования в них элементов типа `interface{}`. К тому же их невозможно обходить с помощью конструкции `for range`.
* **Отсутствие явного указания на реализацию интерфейса типом** затрудняет понимание кода, его модификацию и [рефакторинг](https://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D1%84%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%B8%D0%BD%D0%B3). Компилятор не может автоматически проверить тип на соответствие реализуемым интерфейсам. Также возможна (хотя и маловероятна) «случайная реализация» интерфейса, когда методы типа совпадают по сигнатурам с методами интерфейса, но по смыслу не являются реализацией представляемого интерфейсом поведения.
* **нет обобщённых типов** (generics)

####

### Почему на Go практически не пишут расширений для других языков и динамических библиотек?

### Go - императивный или декларативный? А в чем разница?

**Golang** - императивный язык программирования

**Императивное программирование** — это парадигма, основанная на составлении алгоритма действий (инструкций/команд), которые изменяют состояние (информацию/данные/память) программы. Первыми языками программирования, основанными на таком подходе, были машинные коды и ассемблеры. Фактически, программа на этих языках — это код, который выполняется компьютером сразу, без предварительной компиляции. Из языков высокого уровня, требующих компиляции исходного кода программы в машинный код (или интерпретации), к императивным можно отнести C, C++, Java.

**Декларативное программирование** — это парадигма, при которой описывается желаемый результат, без составления детального алгоритма его получения. В пример можно привести HTML и SQL. При создании HTML мы с помощью тегов описываем, какую хотим получить страничку в браузере, а не то, как нарисовать на экране заголовок статьи, оглавление и текст. В SQL, если нам нужно посчитать количество сотрудников с фамилией «Сидоров», мы напишем `SELECT count(*) FROM employee WHERE last_name = 'Сидоров';`. Тут ничего не сказано про то, в каком файле или области памяти находятся данные по сотрудникам, как именно выбрать из них всех Сидоровых и нужно ли вообще это делать для подсчёта их количества.

### Заповеди Роба Пайка <a href="#docs-internal-guid-82e3458c-7fff-0911-4f71-27deb6234418" id="docs-internal-guid-82e3458c-7fff-0911-4f71-27deb6234418"></a>

<https://habr.com/ru/post/272383/>

**Don't communicate by sharing memory, share memory by communicating.**

**«Не общайтесь разделением памяти. Разделяйте память через общение.»**&#x20;

Этот постулат знают все, он звучал неоднократно в[ докладах](https://www.youtube.com/watch?v=f6kdp27TYZs) и[ постах](https://blog.golang.org/share-memory-by-communicating) посвященным паттернам конкурентного программирования в Go. Этот постулат призван дать понимание сути механизма работы каналов и горутин — ваши функции не делят одну и ту же память, они безопасно общаются, передавая данные по каналам.

**Concurrency is not parallelism.**

**«Конкурентность — это не параллелизм»**&#x20;

Не уверен, что слово concurrency сколько-нибудь удачно переводится на русский, но суть в том, что параллелизм — это просто параллельное выполнение одного и того же кода, а софт, полноценно использующий преимущества многоядерности — конкурентный софт — это конкурентность, тоесть способ структурироания логики программы. Новички очень часто путают эти два понятия. Есть отличное[ выступление Пайка с одноименным названием](https://www.youtube.com/watch?v=cN_DpYBzKso), обязательно посмотрите, кто ещё не.<br>

**The bigger the interface, the weaker the abstraction.**

**Чем больше интерфейс, тем слабее абстракция**

Новички в Go, особенно пришедшие с Java, часто считают, что интерфейсы должны быть большими и содержать много методов. Также часто их смущает неявное удовлетворение интерфейсов. Но самое важное в интерфейсах не это, а культура вокруг них, которая отображена в этом постулате. Чем меньше интерфейс, тем более он полезен. Пайк шутит, что три самых полезных интерфейса, которые он написал — io.Reader, io.Writer и interface{} — на троих в среднем имеют 0.666 метода.<br>

**Make the zero value useful.**

**Делайте нулевое значение полезным**&#x20;

Речь о том, что лучше делать нулевое значение типов полезным безо всяких конструкторов. Конечно, иногда функции-конструкторы необходимы, но если есть возможность сделать переменную вашего типа рабочей «прямо из коробки» — это всегда идёт на пользу. Пример — тип[ bytes.Buffer](https://golang.org/pkg/bytes/#Buffer) или[ sync.Mytex](https://golang.org/pkg/sync/#Mutex) из стандартной библиотеки. Пустое значение — это готовый к использованию буфер, хотя и существуют конструкторы вроде bytes.NewBuffer и bytes.NewBufferString().<br>

**interface{} says nothing.**

**Пустой интерфейс ни о чём не говорит**

Этот постулат говорит о том, что интерфейсы — «поведенческие типы» — должны что-то означать. Если вы создаёте интерфейс, это что-то означает и служит конкретной цели. Пустой же интерфейс (interface{}) ничего не означает и ни о чём не говорит. Есть ситуации, когда его нужно использовать, но они чаще исключение — не используйте interface{} без повода. Новички часто переиспользуют пустые интерфейсы, и масса вопросов на Stack Overflow именно о них.<br>

**Gofmt's style is no one's favorite, yet gofmt is everyone's favorite.**

**Стиль Gofmt — это не чье-то предпочтение, но gofmt предпочитают все**&#x20;

Многие новички, борясь с привычками, жалуются на то, что код в Go отформатирован не так, как им нравится. Gofmt — это единый стиль, он не является чьим-то личным предпочтением. Даже сам Грисмайер, автор утилиты go fmt, сам предпочёл бы другой стиль форматирования. Но с того момента, как формат был утверждён и gofmt используется везде и всегда — просто примите это как должное. Опытные программисты считают go fmt спасением, так как он очень упрощает работу с чужим кодом — ад с разными стилями форматирования в других языках ушёл в прошлое.

Примечательно, что новые языки перенимают этот подход (к примеру,[ rustfmt](https://github.com/rust-lang-nursery/rustfmt)) — это то, о чём говорил Dave Cheney в своем[ выступлении](https://www.youtube.com/watch?v=ulfriuZjGDk)[ «Наследие Go»](http://dave.cheney.net/2015/11/15/the-legacy-of-go) — новые языки больше не будут считаться полноценными без единого стиля форматирования и утилиты, обеспечивающей это.<br>

**A little copying is better than a little dependency.**

**Небольшое копирование лучше небольшой зависимости**&#x20;

Это уже относится к программированию в целом, но в Go это видно и по стандартной библиотеке, и в культуре в целом. Отчасти это перекликается с известной установкой[ «Дупликация дешевле плохой абстракции».](http://us3.campaign-archive2.com/?u=1090565ccff48ac602d0a84b4\&id=92902a19e4\&e=6dbbf45b40) Пайк рассказывает, как в первые дни в Google ему сказали, что больше всего пекутся о реиспользовании кода. Если можно избежать написания одной повторяющейся строчки, сделав импорт — нужно так и поступать. По мнению Пайка, Google до сих пор разгребает проблемы с кодом из-за этого подхода. Очень часто функционал может быть похож (до первого рефакторинга), или необходима лишь часть функционала из зависимости, и зачастую бывает эффективней написать 5 строчек, чем импортировать 150кб зависимостей. Как пример — функция[ IsPrint](https://golang.org/pkg/strconv/#IsPrint) из пакета strconv — она дублирует функционал unicode.IsPrint(), при этом тесты проверяют, что функции работают одинаково. Резюмируя — не бойтесь копирования кода, там где это оправдано.

**Syscall must always be guarded with build tags.**

**Код с syscall-вызовы должен содержать build-теги**

В тему недавно переведённой статьи[ «Как писать Go код, который легко портируется»](http://habrahabr.ru/post/269943/). Некоторые жалуются на пакет syscall в Go — нужно его изменить, он не портируется. Но syscall-ы это по определению платформозависимые вызовы, поэтому если вы хотите делать качественный кроссплатформенный код — всегда добавляйте build-теги в файлы, в которых используются syscall.<br>

**"Channels orchestrate; mutexes serialize"**

**Каналы — оркестрируют, мьютексы — сериализируют**&#x20;

Хороший постулат в тему предыдущей статье ([«Танцы с мьютексами в Go»](http://habrahabr.ru/post/271789/)), о том, когда использовать мьютексы, а когда каналы. Мьютексы просто сериализируют исполнение доступа к чему-либо, но горутины и каналы дают вам инструмент создавать программы со сложной архитектурой и структурой обмена данными между частями программы.<br>

**Cgo is not go**

**Cgo это не Go**&#x20;

Многие радуются тому, как легко в Go использовать C-код. Иногда, это, конечно, необходимо, но Пайк признается, что сам никогда не использовал Cgo, и в мире Go есть четкое понимание памяти, стабильность, безопасность, сборка мусора… и с Cgo всё это идёт в топку. В 90% случаев в Google, когда кто-то говорит «моя программа крашнулась, помогите разобраться» — дело оказывается в Cgo.<br>

**"With the unsafe package there are no guarantees"**

**С пакетом unsafe нет гарантий**&#x20;

Тут делается акцент на том, что код написанный с использованием пакета[ unsafe](https://golang.org/pkg/unsafe/) также не портируемый, и на него не распространяются гарантии обратной совместимости в пределах Go 1 (это написано в первой же строке документации к пакету). Пока что в нём ничего не меняли, но если вы собираетесь использовать зачем-то unsafe — будьте готовы, что в будущих версиях, придётся подстраиваться под изменения.<br>

**Clear is better than clever**

**Ясно лучше, чем заумно**&#x20;

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

**Reflection is never clear**

**Рефлексия никогда не понятна**&#x20;

[Рефлексия](https://ru.wikipedia.org/wiki/%D0%9E%D1%82%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_\(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5\)) (способность программы менять собственную структуру) в Go реализована пакетом[ reflect](https://golang.org/pkg/reflect/), и люди нередко пытаются использовать её не к месту. Рефлексия — это очень-очень мощная вещь, но очень сложная для понимания, и на самом деле нужна очень малому количеству людей и задач. Пайк говорит, что написал, вероятно, больше всех кода с рефлексией в Go, и до сих пор ненавидит это делать. И считает, что нужно стимулировать людей не использовать рефлексию, поскольку она, как правило, не нужна так, как им это кажется.<br>

**Errors are values**

**Ошибки это значения**&#x20;

Ещё один важный постулат, который уже неоднократно[ освещался](http://habrahabr.ru/post/270027/) на хабре, и которому, в частности,[ посвящена статья](http://habrahabr.ru/post/269909/) в официальном блоге Go. Новички часто не понимают этого и спрашивают — «почему я должен везде писать эти if err != nil». Да потому что вы не программируете, вы клепаете код. Многие считают, что if err != nil — это такая альтернатива try..catch… — специальная конструкция языка для работы с ошибками. Но это не так, вы не можете программировать с try… catch… — это управляющая конструкция. С ошибками же в Go можно и нужно делать то, что требует логика программы.<br>

**Dont’ just check errors, handle them gracefully**

**Не просто проверяйте ошибки, обрабатывайте их красиво**

Ошибки очень важно не просто проверять, но и думать, что с ними делать, чтобы ошибочная ситуация была обработана корректно. Возможно нужно дополнить ошибку какой-то информацией, возможно запомнить для обработки позднее, что-нибудь ещё. Огромная и очень важная часть программирования — это как вы обрабатываете ошибки. Не просто проверять и пробрасывать наверх, а думать о том, как правильно обработать эту ошибку. Это справедливо для всех языков, но поскольку в Go ошибки это просто значения, то это проще сделать и проще реализовать красивую и правильную обработку ошибок в коде.<br>

**"Design the architecture, name the components, document the details"**

**Продумывайте архитектуру, называйте компоненты, документируйте детали**&#x20;

Тут речь о важности правильного именования компонентов вашего кода, методов, функций и переменных. Эти имена будут потом находится в коде пользователей вашего пакета. И если имена удачны и понятны, дизайн программы будет более ясен и прост для понимания. Но, конечно, всегда есть детали, которые нужно объяснить — и вот их нужно помещать в документацию.<br>

**"Documentation is for users"**

**Документация — для пользователей**

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

####

### **Что такое type-switch?**

`switch` может быть использован для определения динамических типов интерфейсных переменных. Так, типизированный `switch` использует синтаксис приведения типов, с ключевым словом `type` внутри скобок. Если `switch` объявляет переменную в выражении, то переменная будет иметь соответствующий тип в каждом пункте.

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

```
switch x.(type) {
// cases
}
```

Затем случаи (cases) сопоставляют фактические типы T с динамическим типом выражения x. Как и в утверждении типа, x должен иметь интерфейсный тип, и каждый неинтерфейсный тип T, указанный в случае (case), должен реализовывать тип x. Типы, перечисленные в случаях переключения типов, должны быть разными.

Вместо типа случай (case) может использовать предварительно объявленный идентификатор nil; этот случай выбирается, когда выражение в TypeSwitchGuard имеет нулевое значение интерфейса. Может быть не более одного нулевого случая.

**Пример**:

```
switch i := x.(type) {
case nil:
    printString("x is nil")                // тип i это тип x (interface{})
case int:
    printInt(i)                            // тип i это int
case float64:
    printFloat64(i)                        // тип i это float64
case func(int) float64:
    printFunction(i)                       // тип i это func(int) float64
case bool, string:
    printString("type is bool or string")  // тип i это тип x (interface{})
default:
    printString("don't know the type")     // тип i это тип x (interface{})
}
```

"fallthrough" утверждение запрещено в переключателе типов.

### Как сообщить компилятору, что наш тип реализует интерфейс?

#### Неявная имплементация

> Если это выглядит как утка, плавает как утка и крякает как утка, то это, вероятно, утка и есть.

\
В Go структура с методами будет удовлетворять интерфейсу просто самим фактом объявления метода. Это кажется не особо важным на маленьких программах или искусственных примерах, но **оказывается ключевым в больших проектах**, где приходится думать дважды перед тем как изменить какой-то класс, многократно унаследованный другими классами.\
\
Возможность легко и просто неявно реализовать различные интерфейсы позволяет программам безболезненно расти, без необходимости продумывать все возможные интерфейсы наперёд и не утопать во множественном наследовании. Это к слову о том, что Go задумывался для облегчения жизни в больших проектах.\
\
Важное и не сразу очевидное различие этого заключается в том, как, в итоге, вы строите архитектуру вашей программы — в Java или C++ вы, скорее всего, начинаете с объявления абстрактных классов и интерфейсов, и далее переходите к конкретным реализациям. В Go же наоборот — вы пишете сначала конкретный тип, определяете данные и методы, **и только в том случае, если действительно появляется необходимость абстрагировать поведение** — создаете отдельный интерфейс. Опять же, масштаб этого различия более ощутим на больших проектах.

### Значение nil в Golang

Многие языки программирования также используют концепт nil. Среди его других названий — `NULL`, `null` или `None`. В 2009 году перед релизом Go проектировщик языков программирования Тони Хоар выступил с презентацией под названием «[Null References: The Billion Dollar Mistake](https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/)«. В своей речи Хоар утверждал, что он ответственен за изобретение отсылки null в 1965 году. Он также говорил о том, что указатели в никуда были не лучшей идеей.

> На заметку: В 1978 Тони Хоар также впервые описал принцип взаимодействующих последовательных процессов, или «communicating sequential processes», **CSP**. Его идеи лежат в основе конкурентности Go.

В Go nil является более дружелюбен и менее распространен, нежели в других языках программирования, однако и здесь нужно быть готовым к некоторым проблемам. Nil можно использовать не только по его прямому назначению, о чем говорит Франчес Кампой в своей [презентации](https://www.youtube.com/watch?v=ynoY2xz-F8s) на GopherCon 2016.

Представьте созвездие, где каждая звезда указывает на ближайшую к ней соседнюю звезду. После вычислений, каждая звезда будет куда-то указывать, и нахождение ближайшей звезды становится быстрым [разыменованием указателя](https://golangs.org/pointers).

Однако, пока вычисления не закончены, куда должны указывать указатели? Это тот случай, когда пригодится nil. Nil может значить ближайшую звезду, пока реальная звезда не будет найдена.

В какой еще ситуации указатель в никуда может быть полезен?

### Вызывает ли nil сбои в Golang? <a href="#crush" id="crush"></a>

Если указатель никуда не указывает, попытка разыменования указателя не сработает, что показано в Листинге 1. Разыменование указателя nil приведет к сбою программы. Обычно пользователям такое совсем не нравится.

> Я называю это моей ошибкой в миллиард долларов.
>
> Тони Хоар

Листинг&#x20;

Избежать сбоя несложно. Это вопрос защиты от разыменования указателя nil с [оператором if](https://golangs.org/go-for-if-else-switch#if-else), что показано в следующем листинге.Листинг 2Govar nowhere \*int\
\
if nowhere != nil {\
&#x20;   fmt.Println(\*nowhere)\
}

| 12345 | var nowhere \*int if nowhere != nil {    fmt.Println(\*nowhere)} |
| ----- | ---------------------------------------------------------------- |

По правде говоря, сбой в программе может стать следствием многих причин, не только разыменования **указателя nil**. К примеру, деление на ноль также приведет к сбою, и решение проблемы будет схожим. Даже так, подумайте обо всех программах, написанных в течение последних 50 лет, количество случайных разыменований указателя nil должен быть весьма значительным.

Существование nil обременяет программиста необходимостью принятия дополнительных решений. Должен ли код проверять наличие nil, и если да, то где? Что код должен делать, если какое-то значение равно nil? После всего вышесказанного, так уж ли плох nil?

Вовсе не обязательно постоянно пытаться избегать nil. По правде говоря, в некоторых случаях nil весьма полезен. В дополнение ко всему указатели nil в Go не так популярны, как указатели null в некоторых других языках, и есть способы избежать их использования в случае нужды.

**Вопрос для проверки:**

Каким будет нулевое значения типа `*string`?Ответ

### Защита методов в Golang <a href="#guard" id="guard"></a>

[Методы](https://golangs.org/methods) регулярно получают указатели на [структуры](https://golangs.org/struct), что значит приемник может быть nil, как показано в примере ниже. Происходит ли разыменование указателя явно (`*p`) или неявно через получение доступа к полю структуры (`p.age`), значение nil вызовет сбой.Листинг 3Gotype person struct {\
&#x20;   age int\
}\
\
func (p \*person) birthday() {\
&#x20;   p.age++ // разыменование указателя nil\
}\
\
func main() {\
&#x20;   var nobody \*person\
&#x20;   fmt.Println(nobody) // Выводит: \<nil>\
\
&#x20;   nobody.birthday()\
}

| 1234567891011121314 | type person struct {    age int} func (p \*person) birthday() {    p.age++ // разыменование указателя nil} func main() {    var nobody \*person    fmt.Println(nobody) // Выводит: \<nil>     nobody.birthday()} |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

Скорее всего, сбой вызван после выполнения строки `p.age++`. Удалите данную строку, тогда программа запустится.

> На заметку: Сравните это с аналогичной программой в Java, где приемник null приведет к сбою программы сразу после вызова метода.

Go вызывает методы даже в том случае, если у приемника значение nil. Приемник nil ведет себя так же, как и параметр nil. Это значит, что методы могут защищать от значений nil, как показано в следующем примере.Листинг 4Gofunc (p \*person) birthday() {\
&#x20;   if p == nil {\
&#x20;       return\
&#x20;   }\
&#x20;   p.age++\
}

| 123456 | func (p \*person) birthday() {    if p == nil {        return    }    p.age++} |
| ------ | ------------------------------------------------------------------------------ |

Вместо проверки на наличие `nil` перед вызовом метода `birthday` предыдущий листинг защищает от приемников nil внутри метода.

> На заметку: В Objective-C автоматический запуск метода для nil не приводит к сбою, но при вызове метода будет возвращаться нулевое значение.

С тем, как управлять `nil` в Go, разобрались. Методы могут возвращать нулевые значения, возвращать ошибки или приводить к сбою.

**Вопрос для проверки:**

Что делает доступ к полю `(p.age)`, если `p` является nil?Ответ

### Значения функций nil в Golang <a href="#func-nil" id="func-nil"></a>

{% embed url="<https://golangs.org/nil>" %}
