**Всё про ошибки в Go | Полное руководство для работы и собеседований — Transcript & Summary | SozAI**
Source: https://sozai.app/transcript/common-go-mistakes-complete-guide-interviews/

Разбор обработки ошибок в Go: что такое error как интерфейс, возврат ошибок, нюансы сравнения с nil, паника, recover и типичные ошибки на собеседованиях.

## Key Takeaways

- Ошибка в Go — это значение интерфейса error, проверяется сравнением с nil
- Сравнение интерфейса с nil может давать неожиданный результат из-за динамического типа
- Паника не должна использоваться как обычный механизм обработки ошибок; recover — для крайних случаев

## What the video covers

- error в Go — это встроенный интерфейс с одним методом Error() string
- Ошибки в Go рассматриваются как значения, а не исключения
- Соглашение: функция возвращает ошибку последним (обычно вторым) аргументом
- Пример деления с проверкой деления на ноль вместо паники
- Можно создавать собственные типы ошибок, реализуя интерфейс error
- Нюанс: возврат указателя на структуру ошибки в interface дает не-nil значение даже при nil-указателе
- Внутреннее устройство интерфейса: динамический тип и значение, поэтому сравнение с nil проверяет оба
- Обёртывание ошибок через %w, errors.Is и errors.As, unwrap
- Паника похожа на исключение, recover позволяет её перехватить в defer
- Рекомендации: не строить логику на панике, использовать recover аккуратно, например в HTTP-хендлерах

## Chapters

1. 00:00 Введение и что такое ошибка в Go
2. 04:00 Возврат ошибок из функций и соглашения
3. 04:38 Собственные ошибки и нюанс сравнения с nil
4. 09:00 Обёртывание и проверка ошибок (errors.Is/As)
5. 19:00 Паника и recover
6. 30:00 Практические рекомендации и подходы в командах

Answers

## Questions about this video

Почему ошибка с nil-указателем не равна nil в Go?

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

Что такое паника в Go и чем она отличается от ошибки?

Паника — это аварийное прерывание выполнения, похожее на исключение. Ошибки в Go — обычные значения, которые функция возвращает явно. Паника раскручивает стек, и её перехват через recover в defer считается крайней мерой.

Как правильно обрабатывать ошибки в Go согласно видео?

Возвращать ошибку последним аргументом, явно проверять её после вызова, при необходимости оборачивать контекстом и использовать errors.Is и errors.As для проверки. Панику лучше не использовать как основной механизм управления потоком.

## Full Transcript — Download SRT & Markdown

00:00

Speaker A

Привет. Обработка ошибок в Го является одной из самых популярных тем среди сообщества горазработчиков. И банальная R не равно при неправильном использовании может привести к плачевным последствиям в реальных приложениях. В этом видео я развею все мифы, расскажу, что вообще такое ошибки в Го, как с ними

00:19

Speaker A

работать, что такое паника и как со всем этим связан тифёр. Приятного просмотра. Начнём вообще с простого, как бы, что такое ошибка. Вот, на самом деле, если мы посмотрим, вообще ошибка сама по себе, это на самом деле build встроенный

00:35

Speaker A

интерфейс. И когда пишем вот так вот, да, то есть, если сейчас закомментирую как раз-таки этот интерфейс, то а я увижу, что у меня вот из коробки в Go есть вот такой вот buildты интерфейс, у которого название error. Вот что это за

00:48

Speaker A

такой интерфейс? Значит, этот интерфейс выглядит следующим образом. То есть это буквально интерфейс, у которого есть один методро, который возвращает стринг.

00:58

Speaker A

А симпатически он взращает строчку, которая рассказывает о том, что же случилось на самом деле. Значит, в go ошибки - это значение. То есть вот ещё можете часто встретить такую историю, что вот errors of values там в go говорят. В целом сейчас увидим чуть

01:14

Speaker A

позже, что в go принято обращаться с ошибкой как вот с именно интерфейсом, то есть как с некоторым значением.

01:21

Speaker A

И мы тоже посмотрим разницу между подходами там в той же Джаве или C++, где мы делаем и в GO. Вот, значит, по соглашению, если у нас, понятно, этот интерфейс равен, переменная такого типа такого интерфейса равна, то у нас ошибки

01:37

Speaker A

нету. Понятно? То есть у нас, соответственно есть какая-то ошибка, да? Тут если у нас R не равно, тогда у нас ошибка. Иначе понятно, если R равно, то ошибки нет.

01:46

Speaker A

Вот. А что такое как бы не равно, мы сейчас ещё обсудим. Это тоже довольно такой тонкий момент. Вот давайте посмотрим на простенький примерчик. Вот.

01:54

Speaker A

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

02:09

Speaker A

программу. И, к сожалению, будет очень грустно. На самом деле в Go будет паника, потому что го умные в этом плане, но тем не менее всё равно как бы грустно. Вот давайте попробуем как-то всё-таки этот момент обработать. И понятно, если у нас B0, то что-то

02:23

Speaker A

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

02:35

Speaker A

какое-то значение. Обычное это zero value и ошибку. Вот. Значит, по соглашению вообще в целом в go по конвенции принято всегда возвращать ошибку вторым аргументам. То есть даже если аргументов больше, чем два, условно три аргумента возвращается, то всё равно

02:51

Speaker A

принято возвращать ошибку вторым аргументам. Вот такое соглашение. Вот. Ну как можно как бы этим пользоваться?

02:55

Speaker A

Понятно. Вызываем функцию div. Вот. И смотрим. Если как бы ошибка есть, тогда что-то делаем. Что именно, мы обсудим чуть позже. То есть как конкретные действия будут чуть позже. Более подробная и вот продвинутая история. А иначе делаем что-то другое.

03:09

Speaker A

Концептуальная идея такая, что функция вторым аргументам передаётся, точнее, возвращается значение ошибки. И, соответственно, тот, кто вызывающий, то есть вызывает эту функцию, он может посмотреть, если ошибка была, то что-то сделаем. Вот. Давайте начнём с простого.

03:23

Speaker A

Вот, чтобы вы понимали, в одной компании был инцидент, а, вот из такого такого кода. Давайте посмотрим. Есть функция бар. Значит, эта функция бар, она берёт и объявляет какую-то ошибку. Смотрите, то есть что что важно понимать? Важно понимать, что как быр - это интерфейс,

03:40

Speaker A

то есть никто не мешает написать свою ошибку, согласитесь. То есть поскольку error - это интерфейс, то есть никто не мешает как бы, ну, писать свою ошибку.

03:48

Speaker A

Давайте это и сделаем. Скажем, что у меня будет моя ошибка, my Erроorр, а у которого как раз-таки будет реализован методро, который возвращает какую-то строчку. Вот. Ну, то есть это буквально, ну, реализация своей ошибки. Более того, ну, например, это какая-то редкая

04:01

Speaker A

история, часто такое делают. Плюс ко всему из последнего у меня знакомый был на собеседовании в Озоне. Вот ему как просили: "Напиши свою ошибку". Понимание того, что это интерфейс. Вот. А и такой пример, смотрите. То есть у нас есть,

04:14

Speaker A

значит, наша функция bar, которая что делает? Она объявляет переменную типа указатель на ошибку, ну, на структуру и возвращает из этой функции как раз-таки вот эту переменную. При этом важно, что как бы здесь происходит такой неявный конвершин. То есть у нас, поскольку,

04:31

Speaker A

понятно, эта структура реализует, ну, то есть этот тип реализует интерфейс, мы возвращаем erро, и это вполне легитимно.

04:38

Speaker A

Вот. И тот, кто нас вызывает сверху, понятно, может это вызвать нашу функцию и получить ошибку. Ну, смотрите, здесь казалось бы, что, ну, логика какая у нас? Zero value om - это, то есть кажется, что всё логично. Вот. А, и мы

04:51

Speaker A

здесь вызываем, получается, бар. Тут как бы вернули мы типа а и получили здесь r = равно. Всё прекрасно, как бы должно быть всё о'кей. Вот, на самом деле, если мы вот этот код запустим, то мы увидим здесь fфse. Получается, что

05:06

Speaker A

как бы R на самом деле не равно. Вот как так получилось? Это вопрос очень интересный. То есть, казалось бы, мы вернулись здесь вот ещё раз, да, у нас M - это указатель наро, это вот у нас понятно указатель Zy указатели - это,

05:18

Speaker A

поэтому здесь как бы возвращается, а вот здесь как бы у нас не Нил. То есть как так получилось, непонятно. И на самом деле вот это прям а частая история. То есть прямо, если кто-то работает со своими ошибками, то очень просто так

05:29

Speaker A

ошибиться. В Го в этом месте есть, конечно, проблемы. Давайте обсудим, почему так случилось. На самом деле, как мы помним из вот прошлого, значит, занятия, что у нас интерфейсы, интерфейсы - это на самом деле вот такая вот структура. То есть

05:48

Speaker A

понятно, в случае пустого интерфейса там у нас, э, всё чуть проще. Вот в случае обычного интерфейса у нас есть некоторые данные и указатель на вот таблицу методов методов интерфейса. То есть понятно, некоторые метода. И на самом деле, когда мы сравниваем вот так вот на

06:06

Speaker A

NILл, так вот, когда сравниваем на NILл под капотом, Го проверяет сразу две вещи. Во-первых, он проверяет, а правда ли, что у этого интерфейса есть какой-то динамический тип. Вот. А потом он уже проверяет, как бы на самом деле, правда

06:21

Speaker A

ли, что этот тип сам по себе. Вот. То есть как бы мы, когда сравниваем на равно равно какой-то интерфейс с нилом, проверяется во-первых динамический тип, а во-вторых, проверяется, правда ли, что как бы само значение. Вот. И внезапно, вот если мы сейчас возьмём

06:38

Speaker A

через reflectionш, опять же, пока про рефлекшн я не говорил, но тоже это будет, э, мы выведем тип переменной, а, и значения, да, мы получим, что как бы, да, о'кей, у неё значение у этого интерфейса, то есть динамические значения nilл, но тип у неё нел, то есть

06:55

Speaker A

тип у неё какой-то есть. Имеется в виду, что у интерфейса есть какой-то динамический тип. Стало быть, тогда решили, что пускай он будет не нил. И ровно из-за этого в этом случае мы вот в такой проверке получаем флS. что на

07:06

Speaker A

самом деле довольно неочевид неочевидно с ходу. Вот это такой небольшой нюанс го, котором нужно помнить при работе с ошибками, когда мы свои ошибки какие-то программируем. Мне казалось, что гопрозрачность. Ну я говорю, когда пишете какие-то простые штуки, мы сегодня посмотрим там на примере, как

07:22

Speaker A

написать небольшой сервер, то да, как бы там просто всё. Но когда речь заходит про какие-то тонкости, нюансы, особенно которые любят спрашивать на собеседованиях по ГО, то как бы тут нужно немножко чуть-чуть подумать. Как в этом случае проверять, что дата - это?

07:35

Speaker A

Ну вот, во-первых, тот, кто возвращает, значит, тот, кто возвращает ошибку, должен писать не вот так, а писать вот так. То есть если вот так вот написать, то всё будет о'кей. То есть как бы это вопрос того, кто как бы как возвращает.

07:48

Speaker A

Есть даже линтеры какие-то, вот не помню точно названия, которые это проверяют. Э, насколько помню, такое даже делали.

07:53

Speaker A

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

08:07

Speaker A

очень быстро. Поэтому тут как бы особо в этом плане ничего критического нет, но как бы просто такая тонкость, о которой нужно помнить. О'кей. Значит, давайте немножко разберём такую штуку. Я думаю, что многие могли слышать про мем, про то, что в го часто вот эта вот история

08:23

Speaker A

мемная, что постоянно пишут R не равно R, ну вот это то, что знаете, обычно троллят, что в го постоянно R не равно, пишут R не равно и так далее. Вот эта вот история. Значит, э один из создателей языка Рук Пайк в своё время

08:36

Speaker A

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

08:44

Speaker A

Вот давайте мы на них посмотрим. То есть условно, как задизайнить что-то на го, чтобы постоянно не писать R не равно и чтобы код был лучше. Вот пример, значит, первый. Вот как реализован у нас сканер.

08:57

Speaker A

У нас есть буферизированный сканер. Ну, понятно, буферизированное чтение, оно помогает нам делать меньше сискола в операционной системе, что ускоряет, соответственно, наш работу с в этом случае с чтением, потому что у нас не каждый вызов чтения - это CSC. Вот. И

09:12

Speaker A

какой-то дизайн. То есть, смотрите, дизайн следующего сканера. Мы создаём сканер от какого-то ридера. Вот. И дальше дизайн следующий, что мы как бы читаем, пока вот нам сканер возвращает булин. То есть пока данные есть, мы читаем. Вот. То есть мы что-то делаем с

09:25

Speaker A

этим сканером, а потом у нас есть, соответственно, метод R, который нам возвращает ошибку. То есть мы как бы не каждый раз вот здесь вот при чтении что-то проверяем на ошибку. То есть мы условно текст нам возвращает не ошибку

09:37

Speaker A

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

09:50

Speaker A

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

10:04

Speaker A

возвращать какую-то ошибку вот так вот постоянно вот здесь вот у нас было бы три раза то есть если бы мы вот так вот написали бы да нам пришлось бы здесь понятно каждый раз брать ошибку каждый раз писать вот проверять ещё ещё что-то

10:15

Speaker A

делать это не очень приятно вот поэтому тоже один из подходов такого дизайна как можно избежать по анологии как здесь проверок постоянных это можно опять же завести какое-то полюшко что вот есть ошибка если понятно если дизайн того что вы пишете явно говорит о том что вы

10:31

Speaker A

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

10:45

Speaker A

очень зависит от задачи конкретной, да, но вот идея такая, что в некоторых случаях можно упростить код, чтобы постоянно не писать вот эти вот R не равно и избежать как раз-таки вот этого болеерплейта. Также здесь есть, э-э, я вот специально привёл некоторые фразы

11:00

Speaker A

интересные, которые можно поосознавать, что вот ошибки - это значение, что ошибки - это не какие-то эксепшены, как в Джаве, то есть они могут быть захранены, они могут переданы куда-то и так далее. То есть с ними надо работать как со значениями, что их можно

11:13

Speaker A

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

11:29

Speaker A

кода, то вот проверок видане у вас будет минимальное количество. То есть если у вас очень много проверок не, значит, вы, возможно, делаете что-то не так. То есть подтверждается, что го даёт возможность их избежать. А вот тут опять же история

11:41

Speaker A

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

11:57

Speaker A

есть это не какие-то прервания, это вот именно что некоторые данные. Давайте разберёмся вот как можно на практике работать с ошибками. Сейчас я покажу пример сначала, а, используя только лиbго. Даже даже не только, буквально только Typee свечи, на самом деле, без

12:11

Speaker A

даже сторонних пакетов. А потом мы поговорим про более продвинутые способы. Пример. Я открываю Палик. Кстати, забавный факт. в прошлом году положили, потому что открыли файлик вот не через create, а использовали openфайл, вот и явно передавали здесь вот флаги, а из-за

12:30

Speaker A

этого там флаги были переданы неправильно. И вот было очень грустно. Поэтому тоже опять же вот пример пример того, что чем проще дизайн а вашего пакета, тем лучше. То есть вот условно ореate в чём плюс, да, что есть дизайн.

12:42

Speaker A

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

12:56

Speaker A

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

13:10

Speaker A

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

13:16

Speaker A

Значит, что делается? Мы берём, открываем, значит, файлик. Вот. И дальше случается ошибка. Вот. Значит, что говорят нам авторы Go? говорят следующее, что когда мы пишем бу, мы в целом вальны брать и писать свои собственные ошибки, чтобы не просто

13:33

Speaker A

говорить о том, что случилась ошибка, но ещё и сверху накидывать какого-то контекста. Вот, например, есть PEROR.

13:38

Speaker A

Вот PEROR говорит о том, что у нас какая-то проблема с, понятно, путём файла. То есть вот Pass error - это отдельная ошибка, которая реализует метод error, как вы видите, вот таким-то образом. И у которой ещё есть некоторые методы, которые мы посмотрим чуть позже,

13:52

Speaker A

зачем они нужны. То есть это ошибка, которая помимо того, что она реализует обычный метод, который нужен для интерфейса eror, ну, стандартный error метод, она ещё реализует дополнительные методы для того, чтобы можно было чуть более удобнее работать. Сейчас мы

14:06

Speaker A

посмотрим чуть позже, более продвинутые пакеты. Вот как можно писать по-простому, то есть как бы через Type switch. У нас какая-то ошибка, мы говорим: "О'кей, Team сделал Type Switch". Значит, если это P error, то помните, я показывал, что когда мы

14:20

Speaker A

делаем SE, если мы проваливаемся сюда в кейс, то у нас как бы происходит неявный каст. То есть у нас вот здесь на самом деле наша V - это будет как бы скачанное вот это вот V к вот этому типу, который

14:30

Speaker A

здесь написан. Вот. И мы можем здесь уже пользоваться, соответственно, полями вот этой ошибки. То есть вывести, допустим, пас вывести допустим операцию ещё что-то сделать. То есть, ну, можно просто сделать Type свич, который проходится по ошибкам и смотрит, что

14:43

Speaker A

случилось. То есть, ну, как бы это можно реализовать руками. Тут как бы хороший вопрос: а что делать, когда у меня ошибки вложеные? То есть, например, у меня есть какая-то функция фу, которая возвращает какую-то ошибку. Есть какая-то функция barр, которая тоже

14:55

Speaker A

возвращает ошибку, вызывает функцию F и у неё какая-то логика ещё есть снизу. Мы посмотрим на это чуть позже, как с этим можно бороться. Вот. Но пока идейно всё просто. У нас есть какая-то ошибка, мы можем пройти степ свичом и проверить,

15:07

Speaker A

что случилось. Вот здесь специально написано в close вот так вот без дефёра, потому что дефр будет сегодня чуть позже. Вот. Но утверждение, когда вы пишете какую-то или работаете с какими-то пакетами, у них, скорее всего, будут свои ошибки какие-то более

15:18

Speaker A

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

15:31

Speaker A

другую функцию вызывает, и вот так по цепочке происходят вызовы. А для этого есть специальная ошибка, которая находится в определённом пакете. Сейчас мы посмотрим, что это за пакет, то есть как это работает. говорят: "О'кей, давайте сделаем". Вот есть ошибка

15:44

Speaker A

обычная, у неё хранится что? Ну вот меседж и некоторая ошибка. Вот. А если у нас ошибок несколько, условно, мы хотим мы хотим в одну ошибку записать сразу много ошибок. Как мы это сделаем? Мы возьмём, храним медж и похраним просто

15:57

Speaker A

слайс ошибок вот таким образом. И реализуем опять же некоторые методы. Сейчас мы посмотрим, какие. То есть зачем я это рассказываю на самом деле вот как в реальности пользоваться ошибками. Пример у нас есть программа, которая сделает следующее. она читает

16:12

Speaker A

какой-то конфиг, то есть какой-то конфиг приложения. Как работает эта функция? Она берёт и говорит, что так и так, а случилась там какая-то ошибка вот из такой-то функции.

16:23

Speaker A

Вот. И что мы делаем? Мы говорим: "О'кей, как бы мы мало того, что хотим прокинуть эту ошибку вот из этой функции, мы ещё хотим добавить какого-то своего контекста". Вот для этого есть в пакете FMT специальная функция RРФ, которую чаще всего используют, когда

16:37

Speaker A

работат с ошибками. Как она работает? Она позволяет через, соответственно, процент W передать вам несколько ошибок, которые будут вложены. Вот. То есть, если мы зайдём вот в ток этой функции, нам скажут, что, значит, если у нас вот этих процент W несколько, вот, то нам

16:56

Speaker A

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

17:07

Speaker A

дальше зачем это нужно? То есть казалось бы, о'кей, у нас есть какие-то разные ошибки, мы хотим что-то сделать по факту. Мы хотим взять и как бы свернуть их в одну ошибку. Как мы их сворачиваем в одну ошибку? Очень просто. Мы говорим,

17:17

Speaker A

что у нас есть просто, понятно, структура, реализующая интерфейс, внутри которой хранится, ну, слайс ошибок, как бы. О'кей. Что дальше? На самом деле дальше можно удобно пользоваться специальным пакетом Errors. У него есть некоторые extension, которую мы сегодня тоже посмотрим, как это выглядит. То

17:31

Speaker A

есть я говорю: "Прочитай config. Если ошибка, то я хочу что сделать? Я хочу проверить, правда ли, что эта ошибка - это ошибка того, что у меня, значит, файлы не существует. Вот если это правда, тогда я могу что-то сделать.

17:44

Speaker A

Потом, что я могу ещё сделать? Я могу сказать: "О'кей, давайте попробуем сказать, что эта ошибка, это ошибка того, что у меня проблемы с путём". Вот.

17:52

Speaker A

То есть то же самое, как мы, я показывал Type Switch. То есть на самом деле эта конструкция - это один в один сви, только под капотом вот RS делает немножко умную логику. Сейчас посмотрим какую. Но идея какая, что мы можем вот

18:03

Speaker A

через fнтрф мы можем взять и вот здесь вот написать. Ну, обычно пишут один раз по W, то есть условно вот эта функция, она вызывается какой-то ещё функцией. Та функция тоже может написать процент W. И у нас получается вот такой вот

18:16

Speaker A

слайс ошибок вложенный. А потом мы можем что делать? Мы можем, используя erroris, спрашивать, правда ли, что вот в вот в этот R - это буквально на самом деле под капотом слайс ошибок. Правда ли, что внутри этого слайса есть хотя бы одна

18:29

Speaker A

такая ошибка? Или правда ли, что мы можем взять и сконвертить вот эту ошибку в такую ошибку? Как это работает?

18:35

Speaker A

Смотрите, давайте на erрос посмотрим, как он работает. Erрос под капотом что делает? Он пытается сделать следующую штуку. Он пытается взять текущую ошибку и посмотреть, есть ли у неё метод unwrap вот таким-то. Вот на самом деле очень такой редкий синтаксис для go. А оно

18:49

Speaker A

делает в следующем следующую штуку. Она берёт, говорит: "О'кей, есть ошибка". Если у этой ошибки есть метод unrap, аrap что делает? Он как бы распаковывает. Он берёт, возвращает как бы условно предыдущую ошибку. Вот.

19:00

Speaker A

делается unрап. Если, понятно, у нас можно пойти дальше, оно идёт дальше. То есть, э, как бы оно как работает, оно берёт под капотом, вот заставляет ошибку реализовывать метод is. Вот если у ошибки этот метод реализован, тогда, соответственно, можно просто его

19:13

Speaker A

вызвать. То есть ещё проще. То есть условно я как разработчик библиотеки могу переопределить этот интерфейс, ну, то есть реализовать его, и у меня функция вот эта вот в пакете Erors возьмёт и попробует просто сконвертить, понятно, чейн ошибок в мою ошибку. То

19:28

Speaker A

есть, э-э, ещё раз, да, у нас есть, значит, возможность через FMTRF брать и чейнить ошибки, то есть складывать их как бы в одну. Как это работает под капотом? Вот так вот. Под капотом просто это слайс ошибок и отдельная ошибка,

19:41

Speaker A

которую это оборачивает. Потом у нас есть функция errors. Она позволяет получить були. Правда ли, что вот в цепочке это этих ошибок существует такая ошибка? ВотRS позволяет как раз-таки сконвертить и сказать, что можно ли, пожалуйста, взять и вот из этой ошибки

19:56

Speaker A

получить такую ошибку прямо вот явно скастить структуру. То есть понятно, она работает по аналогии, пытается заанрапать и смотрит, есть ли такая ошибка внутри. На самом деле логика простая, но реализация такая вот глиняная немножко. То есть что берём как

20:07

Speaker A

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

20:20

Speaker A

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

20:39

Speaker A

представьте, если у вас ошибка вот на таком уровне, вы бы хотели бы её, конечно, вложить, чтобы она, ну, как бы понятно, проросла наверх. Более того, там есть куча всяких способов, а как же правильно? Вот условно мы же не хотим, чтобы у нас код

20:53

Speaker A

на уровне опишки нашей в приложении знал что-то про ошибки на уровне базы, поэтому там делают мапинг ошибок, то есть мапят ошибки базы там в ошибке кейсов репозитория и потом прокидывают наверх. Вот мы тоже этим займёмся. Это уже более вот к архитектуре приложения

21:08

Speaker A

вот разговор. Но идея такая, что мы как бы хотим уметь ошибки чейнить и прокидывать. Вот. И буквально вот так.

21:14

Speaker A

Потому что, опять же, мы хотим на верхнем уровне, например, проверить, правда ли, что эта ошибка вот такая или ошибка вот такая. Понятно? То есть проверять, правда ли, что в этой цепочке есть какие-то ошибки. Вот. О'кей.

21:24

Speaker A

Давайте дальше. Есть более продвинутый пакет. То есть есть вот дефолтный пакет, который erors, а есть его как бы более продвинутая версия. У неё есть разные прикольные функции. Например, значит, можно создать ошибку, внутри которой будет приложен, значит, steкт. Вот тоже

21:44

Speaker A

удобно. Можно создать, опять же, вот есть unraap дефолтный, да, можно создать ошибку с месседжем каким-то. Ну, опять же, на самом деле, что типа rрф, только чуть удобнее. Вот можно спросить кос, то есть условно получить parрента в ошибках. То есть, ну, это функции,

21:58

Speaker A

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

22:05

Speaker A

Прямо, если хочется, чтобы в ошибке был какой-тотрейс вызовов, можно это сделать и прихранить его здесь. Это не то, чтобы эффективно, но так по жизни иногда делают. Вот. Соответственно, опять же пример, у нас есть функция фу, которая возвращает какую-то ошибку и говорит,

22:19

Speaker A

что вот у нас будет какая-то там врап, мы создаём новую ошибку, как вот такую ошибку под капотом и некоторый месседж.

22:26

Speaker A

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

22:35

Speaker A

Потому что, понятное дело, у нас это интерфейс, это указатель на какую-то структурку под капотом, поэтому здесь вс, понятное дело, передаётся. Ну вот нельзя вот так написать, понятное дело, то есть так не работает, потому что эта штука создаёт новую errors news. Errors

22:50

Speaker A

new создаёт новую ошибку, то есть новый указатель на структурку интерфейса. И понятно, здесь отработать не будет. То есть, если мы хотим использовать Рыс по жизни обычно просто объявлены ожитие ошибки где-то, понятно, в пакете, и мы можем просто проверять, правда ли, что у

23:05

Speaker A

нас в этом чейне ошибок есть такая ошибка. Сильно ли влияют эти проверки на performance. Значит, опять же, это очень тонкий вопрос, как бы, да, это медленнее будет работать. Мы сегодня тоже посмотрим примеры, допустим, стрейкичами. Можно тоже в год сделать их

23:18

Speaker A

на паниках, там ещё будет медленнее. Но вот если вопрос про то, что медленней вот так вот или руками пытаться как-то вот делать Рнер Unнил. Ну, понятное дело, что, конечно, такой медленней, потому что там под капотом есть каста, вот эта функция и то уже не бесплатная.

23:32

Speaker A

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

23:43

Speaker A

Опять же, есть исключение, если я пишу какое-то что-то быстрое, что требует, соответственно, скорости, понятное дело, я буду отказываться вообще от всего. Я уже, как говорил, там есть доклады на том же Gold Конфе про то, что ребята взяли вообще выкинули все интерфейсы из

23:56

Speaker A

программы просто потому, что так быстрее, как бы. Ну да, о'кей, это правда. То есть мы экономим на на секунды на такой такой истории. Вопрос, надо ли это всем? Нет, это надо конкретно там, где у нас есть какая-то большая нагрузка и мы точно знаем, от

24:06

Speaker A

чего мы отказываемся. Но, конечно, да, такой подход он будет медленней. Но опять же в реальной жизни 95% кода, который вы будете писать, если это не какоя-то системная история, он обычно идёт в пользу читаемости для других людей, нежели скорости. Ну, понятно,

24:22

Speaker A

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

24:29

Speaker A

Но если вы хотите битовые сдвиги писать, чтобы просто быстрее чуть работало, ну, как бы не надо, потому что другим людям будет это сложнее читать. О'кей. А, небольшой спойлер, Go 126 ещё не вышел, но я почекаутил ветку, которую сейчас

24:41

Speaker A

разрабатывают новую версию языка. Вот. И там добавят новую функцию, она будет называться STE. Вот она будет работать точно так же, как RR вот RRSS, то есть то же самое, как эта функция, только чуть более удобнее.

24:55

Speaker A

То есть теперь понятно, нам не нужно передавать э в параметры сюда ошибку. Мы просто её параметризируем эрром. Вот. И дальше нам возвращают то, что нужно. Вот тут довольно просто. Вот. То есть будет такая функция, которая позволяет чуть более удобнее работать с ошибками, что

25:14

Speaker A

вот не может не радовать. Вот её опять же ещё нету, она появится только в Go126. А, соответственно, что, ну, вот довольно приятно. Приятно, что такое есть. О'кей. Кстати, то, что интересно, используется вот указательно указатель, чтобы можно было передавать в S и делать

25:32

Speaker A

такой Lazy Location. тоже из интересного. Вот история про то, как это дизайнт. Значит, кому интересно, опять же в целом, давайте небольшая предыстория. В эту функцию хотели добавить ещё в 118, когда только дждерики появились. Почему её не сделали, непонятно, ну и бог с ней, как

25:49

Speaker A

бы люди жили и жили нормально, не очень страшно. В значит go тоже не сразу полись функция, её добавили потом. Она называется er join. В каком-то смысле er join - это то же самое, что вот эта штука, то же самое, что FMTRRF с просто,

26:06

Speaker A

понятно, множеством вот таких вот процент W. Вот. Но она более чуть красивая. То есть когда вам не нужно никакое сообщение передавать, вы просто хотите сжойнить ошибки. Функция copy and close. Как она работает? Понятно. Она принимает какое-то src, DT. Вот. И

26:20

Speaker A

пытается что сделать? Она пытается взять записать данные вот из как раз-таки нашего СРЦ. А потом взять закрыть понятно дескрипторы. Вот. Ну и что может получиться? Вот может так получиться, что у нас случилось какая-то ошибка, и мы ещё и закрыть не смогли. По-хорошему,

26:38

Speaker A

как бы, конечно, можно забить. Вот обычно наро забивают очень сильно, потому что, ну, типа, пофиг, там не смогли закрыть. Ну, ладно. Но в целом это не очень хорошо. То есть как бы лучше, конечно, это залогировать. То есть best effр, как говорится, это

26:50

Speaker A

взять, это прокинуть наверх, чтобы это было видно. Поэтому по-хорошему сделать join, сказать, что так и так, у нас такая-то ошибка. Ещё вот не получилось закрыть, надо что-то с этим сделать. По жизни, конечно, понятно, если у вас какая-то сетевая история, вы не смогли

27:01

Speaker A

закрыть ресурсы, это, конечно, критично. То есть я не говорю, что всегда нужно забивать на закрытие, но обычно это всё равно на это. Есть случаи, когда не всё равно, как я сказал, допустим, когда мы не смогли закрыть какой-то ресурс

27:11

Speaker A

сетевой, то понятно, как проблема, у нас утечка, другие не смогут к неё получить доступ. Вот. Но если вы где-то увидите просто вот так, то как бы знаете, что, ну, люди просто, это значит, что люди забили и этот голос он ни на что не

27:22

Speaker A

влияет. Такое бывает в жизни. То же самое с вот таким примером. То есть, понятно, он немножко не очень хороший пример, на самом деле. Вот. То есть, э, понятно, это пример с файлом, когда мы вот здесь что-то поделали ещё потом вот

27:36

Speaker A

после этого дефёра. Про про дефёр ещё не рассказал, поэтому не очень хорошо здесь. Но, в общем, идея в том, что если мы помимо того, что не смогли закрыть файл, ещё у нас была какая-то ошибка, то как бы давайте не просто скажем, что у

27:47

Speaker A

нас какая-то ошибка, а ещё и файл не смогли закрыть. То есть очень часто пишут просто вот так. На самом деле это прямо частая история. И даже влибе так пишут. Вот. Но как бы лучше всегда всё-таки закрытие файла обработать, явно

27:59

Speaker A

передать наверх, что случилось какая-то проблема. Вот. Почему можно вот так делать и что такое def на name параметр, я расскажу сегодня чуть позже. Вот кто не не понимает, пока не нужно волноваться. Как бы просто вот утверждение следующего, что можно

28:14

Speaker A

заджойнить ошибку закрытия файла и ещё какую-то ошибку, которая была сверху, не забив при этом на ошибку закрытию. Это как бы важно. Ну понятно. Опять же, важно в некоторых случаях как бы такой небольшой баланс. О'кей. По поводу кастомных ошибок. Смотрите, как я уже

28:27

Speaker A

сказал, вам в целом никто не мешает писать свои кастомные ошибки. То есть можно написать какую-то свою ошибку, в неё засунуть какие-нибудь поля, написать ей метод error. Более того, можно написать вот такой метод is. И как мы помним, у нас под капотом er как

28:42

Speaker A

раз-таки, да, он что делает? Он как раз-таки под капотом проверяет, есть ли такой метод реализован у ошибки. Вот здесь вот таким образом. У него на самом деле очень такой странный синтаксис, то есть он мало где встречается. Вот то,

28:53

Speaker A

что мы делаём кастим прямо вот в объявление, а, на месте, ну, inп placeйс, короче, да. То есть если такой метод есть, тогда он его вызывает. Вот можно вполне спокойно объявить такой метод, чтобы как-то переопределить поведение. То есть это довольно удобно.

29:06

Speaker A

Опять же в своих ошибках можно переопределять какую-то логику. Важно на неё, конечно, не завязывать бизнес бизнес-правила. Это понятное дело. То есть какую-то сложную логику говорить не стоит, но если у вас какие-то там мёрзт ошибки, то вот можно как-то это сделать

29:19

Speaker A

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

29:33

Speaker A

довольно сильно связан с ошибками. Вот смотрите, такой примерчик у нас есть. Понятно по srcфайл, dstфайл. Вот мы там понятно. Получаем текущую директорию.

29:42

Speaker A

Берём джойним пути. Неважно, у нас есть srcфайл, dstil. Вот, значит, что мы хотим сделать? Мы хотим взять и, понятно, из srcло все данные в деп. Вот.

29:53

Speaker A

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

30:07

Speaker A

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

30:18

Speaker A

общем, идея такая, что нам много раз нужно вставлять закрыть ээ ресурса в разные части функции. То есть, ну, это грустно, как бы, какой-нибудь Джаве, это было бы понятно трай с ресурсами, вот, либо понятно файли как-нибудь, если попро, ну, это более старая версия Джава

30:33

Speaker A

и закрывать. Вот в C++се, понятно, можно было сделать какой-нибудь деструктор, который бы это делал вот через раино вот в Гонепонятно, как это делать. Типа у нас есть ресурсы, которые нужно постоянно закрывать в разных частях функции, чтобы не забыть это сделать.

30:46

Speaker A

Вот для этого был придуман. Вот что такое? Def - это возможность сделать какое-то отложенное действие. То есть я говорю: "Давай-ка, когда эта функция завершится, неважно, как она завершится, сделай, пожалуйста, закрытие вот этого ресурса". То есть in clos. Вот то же

31:01

Speaker A

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

31:15

Speaker A

такое-то действие. Ну, по факту не действие, а конкретно мы передаём функцию и аргументы этой функции, что удобно, как бы. То есть там не нужно постоянно писать много раз, мы пишем один раз в каком-то месте нашей функции.

31:25

Speaker A

Вот давайте разберём некоторую задачу с собеседований буквально это прямо когда идёшь на какие-то языковые секции пого там постоянно такое спрашивал вот из того, с кем я общался, люди, которые были на курсах, у меня говорили постоянно, что вот там с дефёром много

31:39

Speaker A

задачек. Вот смотрите, есть такая штука. У нас есть структурка usеer, а у неё есть имя. Ну понятно, как бы просто тип user с полем. Что мы делаем? Мы берём, понятно, создаём структуру usеer, говорим: "Напечатай, пожалуйста, DH". То есть делаем def в конце мейна возьми,

31:57

Speaker A

вызови функцию Fitle и напечатай вот потом после того, как мы сказали: "Сделай в конце-то", инкрементируем H и делаем return. Вот. На самом деле можно было не писать, но ладно. Вот как бы вопрос, что будет выведено? Не очень понятно, да? С одной стороны, как бы у

32:13

Speaker A

нас D инкремитируется, вот как бы должно быть один по-хорошему здесь выведено. С другой стороны, непонятно. Ну, как бы на самом деле те, кто разбирается в том, как языки программирования устроены, компилируются, какие стадии компиляции и так далее, тут самое понятно, что вот у

32:29

Speaker A

этой штуки хотелось бы на каком-то месте вычислять аргументы, то есть как-то понимать, что передано. И на самом деле в го это выглядит снящи образом. То есть, если мы запустим код, будет как раз-таки здесь у нас нолик. Почему?

32:42

Speaker A

Потому что, значит, у нас сама функция, то есть важно, что сама функция - это тоже как бы некоторо в некотором смысле значение. То есть, ну, нам никто не мешает сделать, понятно, вот так. Значит, можно сделать проще вот так, как бы не очень

32:55

Speaker A

важно. То есть функция - это на самом деле объект первого класса, её можно класть переменно. Вот. И def он вычисляет саму функцию, то есть что будем вызывать и аргументы в момент объявления. Написано вырезка небольшая из стандарта. Вот. Значит, э-э, поэтому

33:09

Speaker A

у нас здесь TH вычисляется, когда мы пишем deф, поэтому здесь будет ноль. А если в вызывалась функция, которая выводит DH? Вот это хороший вопрос. И буквально как бы тоже на тех же собеседованиях обычно спрашивают: "А вот как это пофиксить?" Ну вот, на самом

33:24

Speaker A

деле, это фиксят следующим образом. Можно сделать просто лямбду, вот такую лямбду. То есть понятно, правила сохраняются, мы как бы всё о'кей, вычисляем функцию в момент объявления.

33:33

Speaker A

Аргументов здесь нет. И просто в самой вот этой лямде в итом обращаемся к дайджу. Вот, понятно. Это у нас замыкание, которое хранит, то есть замыкание всегда в любом языке программирования, это указатель на функцию и контекст. Вот. Ну и понятно, у

33:46

Speaker A

нас в контексте лежит D, оно потом инкредитируется, можем обращаться к ней и получить единичку. Вот здесь будет вполне ожидаемая единичка. Когда мы не хотим привязываться кругметом, можно просто обернуть всё в лямду. Почему оно негирирует лямбду автоматически? Ну, потому что так решили сделать. То есть

33:59

Speaker A

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

34:12

Speaker A

возможность, просто такой дизайн. Так решили. Вот. Ну опять же, почему так решили? Ну потому что, скорее всего, обычно тебе лишняя лям. Вот, то есть ты вряд ли хочешь сделать обычно лишнюю лямду просто так. То есть это ещё не

34:22

Speaker A

очень бесплатно. Поэтому способ, как это сделать, он вот такой вот. Более того, мы увидим чуть позже. Зачем-то нужно.

34:30

Speaker A

Вот в Го, как я уже рассказывал, существует возможность обращаться к именованным возвращаемым значением. То есть, например, что можно сделать? Можно сказать, что я возвращаю 42. Вот это 42 - это на самом деле уже именованная переменная рес. И в дефёре я могу к ней

34:46

Speaker A

обратиться, у меня будет выведено 43. Почему так? Потому что, опять же, с точки зрения стандарта у нас функция вот эта вызывается, а, значит, э то есть до того, как на самом деле у нас случился сам return. То есть то есть как бы

35:01

Speaker A

смотрите, до того, как мы положили сюда что-то, какие-то пере какие-то данные, вот, ну, помните, вонре я показывал непосредственно вот в фреймпоинтере после аргументов мы вызовем эту функцию.

35:13

Speaker A

Итого мы можем брать и обращаться к name параметрам в дефре, то есть и их менять.

35:20

Speaker A

Зачем это нужно? Вот смотрите, это как бы очень плохо на самом деле делать. Это грустно. То есть так по жизни надо, но очень редко. Мы сейчас увидим буквально одну ситуацию чуть позже, когда это надо. Вот. Но факт в том, что, да, у

35:29

Speaker A

нас, э, значит, понятно, вот с точки зрения стандарта, опять же, у нас функция вызывается после того, как у нас засотились параметры вот здесь вот, то есть, как мы присвоили сюда 42, но до того, как мы фактически положили эти

35:41

Speaker A

данные вот на стек, то, что мы рассматривали в Асндере, и поэтому def в этом случае отрабатывает и получает возможность как бы менять вот эту переменную, которая возвращается. Это мега неочевидно, это мега несчитаемо, но это нужно вот буквально в нескольких

35:55

Speaker A

случаях. Мы увидим чуть позже, каких. Давайте посмотрим вот такой вот примерчик. У нас есть интерфейс doc. У него есть, понятно, какой-то метод бак, есть реализация, овчарка. Вот. И что как бы происходит? Смотрите, мы это, если что, сейчас мы разбираем такие тонкие

36:10

Speaker A

моменты. То есть на самом деле в целом довольно тупо и понятно, типа deфр вызывается в конце функции там 90% случая всё о'кей. Мы сейчас разбираем такие тонкие моменты. Смотрите, что будет в таком случае, если мы объявим переменную типа doc- это интерфейс

36:25

Speaker A

zerвеell интерфейса. Как мы помним, это, то есть здесь эта штука будет л. Дальше мы вызовем, скажем, что мы хотим в конце вызвать вот такой вот метод, а потом присвоим к переменной некоторые, ну, то понятно, некоторое значение сюда засудим. Вот. И потом ещё, допустим,

36:41

Speaker A

вызовем передфором ещё разочек. Ну, в смысле, перед фёром ещё разок вызовем. Вот. Не очень понятно, что будет.

36:46

Speaker A

Казалось бы, вот здесь deфре как бы будет точка barк. Мне очень понятно, что произойдёт. То есть давайте так, как бы, э, если я сделаю сейчас вот так вот, то у меня будет паника. Вот. Ну, в целом, как бы понятно, почему у меня нет

37:01

Speaker A

реализации. Вот. Но непонятно, как бы в дефёре же я беру после него присваиваю всё-таки значение. На самом деле, если мы какой- запустим, то у нас тоже будет всё очень грустно. При этом, что важно, смотрите, у нас паника будет не в момент

37:16

Speaker A

вот здесь вот вызова, то есть мы как бы сюда даже не дойдём. То есть мы до этой строчки даже не дойдём. Почему так?

37:21

Speaker A

Потому что опять же так устроен, что если у нас то есть когда мы deф пишем под капотом, там потом компилятор getрит код, который что делает, он сперва смотрит на, понятно, что мы вызываем, пытается найти функцию, которую мы вызываем. То есть вот

37:36

Speaker A

doc.bark, оно будет пытаться найти конкретную функцию, которую мы вызываем. У нас её не будет, потому что у нас, понятно, ну, вот и что важно, что у нас исполнение оно прервётся, то есть будет л в момент объявления дифра. Мы даже вот

37:49

Speaker A

вот условно мы сюда не пойдём даже вообще. Вот. То есть, если посмотрим на вывод, мы здесь даже не побываем. Мы как бы уберём сразу вот тут. Вот. Это такой тонкий момент. Опять же, как бы в жизни он вряд ли пригодится вам, потому что,

38:00

Speaker A

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

38:10

Speaker A

Поэтому надо понимать, что вот фёр он как бы понимает, что вызывать. Если он не понимает, он кидает панику. Это такое простое очень объяснение. Более сложное, что понятно, мы берём и вылетим буквально указательно функцию, которую мы вызываем. Если мы не можем его

38:23

Speaker A

завалейтить, то всё очень грустно. Кидаем панику. Вот. Вот такой вот примерчик. О'кей. Ну, тоже как бы довольно очевидный пример, но тоже как бы его стоит понимать, что если у нас много дефёров, то опять же по вот нарту у нас они вызываются в обратном порядке.

38:37

Speaker A

То есть у нас будет сперва три, потом два, потом один. У нас дефёры вызываются в обратном порядке. Ну, в целом это логично. как бы идём снизу вверх и вызываем, как они объявлены. А если поменять doк на другую реализацию

38:49

Speaker A

интерфейс? А если поменять docг на другую реализацию интерфейс? Не очень полный вопрос. То есть если вот так сделать, в смысле, если вот так сделать, я считаю, что да, оно заведётся. Ну, на самом деле, оно заведётся ровно так же, как вот

39:01

Speaker A

буквально, например, вот такой дог барк. Ну, то есть понятно, понятно, почему в целом, потому что что такое барк. Бак - это на самом деле просто функция вот такая, которая принимает некоторые this на вот эту штуку. и выводит строчку. То

39:15

Speaker A

есть никто не мешает здесь вызвать барк от нила. Ну потому что как вот, ну опять же здесь будет л, очевидно, потому что Zer value и никто не мешает вот так вызвать, потому что понятно, под капотом просто мы передаём здесь this, будет л,

39:28

Speaker A

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

39:39

Speaker A

Вот опять же по стандарту у нас такая вырезочка небольшая. Ну, это как бы интуитивно, типа было бы странно, если это было бы не так. О'кей, небольшой антипаттерн. А, все вы знаете, давайте история. Вот все вы знаете, что там есть

39:50

Speaker A

трансляции на ВК, YouTube. А вот, э, чтобы вы понимали, это типа не какой-то стрёмный пример. То есть реально так бывает люди ошибаются и там в больших проектах, а дефран сам по себе не бесплатный. И когда вы вообще в целом,

40:04

Speaker A

давайте глобально, типа, если вы в цикле алоцируете какой-то ресурс, а, новый или вы в цикле что-то создаёте, то почти всегда это ошибка. То есть почти всегда можно это вынести за цикл. И вот фёрн сам по себе не бесплатный, потому что

40:16

Speaker A

понятное дело, что мы на стек кладём некоторые инструкции, что их нужно вызвать. И если мы много раз напишем def, ну, если цикл довольно большой, то у нас может случиться переполнение стека. Ну, на самом деле не переполнение, а на самом деле лик

40:28

Speaker A

некоторый. То есть у вас просто будет ээ некоторый лик по памяти, но на самом деле может ещё и переполнение случиться.

40:33

Speaker A

То есть там зависит от вот и была история, что там рестример, который стримит на ВК YouTube, он как бы умирал, потому что вот была в форе вот такая штука. Вот поэтому такой небольшой антипаттерн deфр в цикле лучше не

40:48

Speaker A

писать. Даже видите, гон подсказывает, что это проблема. Вот. Ну потому что дефёр он не бесплатный всё-таки. То есть он Давайте, он не сильно дорогой. То есть, если бенчмарки глянуть, то там deфр не очень дорогое удовольствие, но если их много, то там уже получается

41:02

Speaker A

больновато. Больновато вплоть до того, что приложение может просто умирать. С дифором разобрались. То есть в целом глобально это просто возможность вызвать функцию после в конце выполнения другой функции, да, глобально. Ну, как бы есть некоторые нюансы вот, которые мы

41:15

Speaker A

обсудили. Кстати, забыл сказать, исходники кода из этого видео и другие закрытые полезные материалы ты сможешь найти в моём Telegram-канале.

41:23

Speaker A

Подписывайся и становись частью нашей большой и дружной семьи. О'кей. Паника. Смотрите, паника - это очень весёлая штука. Это тоже встроенная. То есть, что паника - это если открыть билтын, то паника - это вот встроенная функция в язык. Билн функция. Вот. И,

41:39

Speaker A

соответственно, она была добавлена не просто так. Вот смотрите, все вы помните вот эту функцию, вот мы её с вами писали, которая берёт и по индексу возвращает руну. То есть важно, что это не байтик, это именно руна. Вот. И как

41:52

Speaker A

бы не очень понятно, что делать, если мы прошлись по строчке и у нас не оказалось нужных, понятно, данных. То есть у нас не оказалось нужного индекса.

42:03

Speaker A

По-хорошему, конечно, возвращать ошибку. То есть типа not found, вот это всё вот как можно ещё делать? Смотрите, в общем, что делает паника? Паника - это очень весёлый механизм. Сейчас я чуть позже расскажу, как он именно работает более формально, но идейно это то же самое,

42:16

Speaker A

что вот New Exception в Джаве. Вот. или какой-нибудь фроу в C++, ну, то же самое как в C++се кинуть эпtion. Вот. То есть это просто возможность работать с ошибкой не как вот со значением, а вот её пробрасывать наверх. Мы чуть позже увидим, что там

42:31

Speaker A

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

42:42

Speaker A

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

42:52

Speaker A

Утверждается, что их можно использовать в двух случаях. Первый случай, когда у нас есть какой-то unreachable code. То есть, условно, вот я знаю точно, что у меня вот сюда мы не дойдём никогда. Ну, условно там это можно видеть, когда у

43:03

Speaker A

нас есть какой-то свич по каким-то типам. Вот, ну, например, у нас есть э какой-нибудь sвиt, и мы точно уверены, то есть мы точно знаем, что сюда мы не придём никогда. То есть, если мы пришли сюда, значит, какая-то проблема

43:16

Speaker A

случилась, там нужно кинуть панику. То есть вот утверждается, что как бы если у нас мы точно уверены, что код unrechable, то всё о'кей. Вот опять же как бы понятное дело, что точно мы не можем никогда быть уверены, потому что

43:28

Speaker A

понятно, какой-нибудь разработчик придёт и пишет код, всё нам сломает и вряд ли не будет выполняться. Но почему тогда иногда так делают? Потому что банально лень писать ошибки. Вот. То есть как раз-таки второй пункт, он связан с первым, когда у нас есть какие-то

43:41

Speaker A

внутренние функции с strong recovery вариант. Вот strong recoverant, это сейчас я чуть позже расскажу, что такое, но идея такая, что, короче, если у меня есть какие-то функции, допустим, фу, там бар, ещё какой-нибудь example, э, допустим, это какие-то прочие парс А,

43:58

Speaker A

давайте парс B и парс C. Вот у меня, например, какой-то парсер. И вот у меня, например, парсер А вызывает какой-нибудь парсер B. парсер Б там вызывает парсер С. И мне очень как бы было бы грустно, особенно если я очень часто это

44:12

Speaker A

использую, постоянно ошибки передавать вот здесь вот. Конечно, так правильно, конечно, так более дематично, но иногда так лень, что, да, паники используют.

44:22

Speaker A

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

44:38

Speaker A

потом всё-таки эту панику поймал. Как её поймать, опять же, я расскажу сейчас чуть позже подробнее, но идейно её можно понять поймать вот так. То есть допускается использовать панику, если вы уверены, что кто-то сверху её словит и вам очень-очень лень возвращать ошибку.

44:53

Speaker A

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

45:05

Speaker A

лень вот это постоянно выносить ошибки вот эти. Вот. Поэтому иногда паника допустила в этом случае. Но, конечно, по жизни, если можно её не писать, лучше не писать. Поэтому паника она, вот, как я сказал, раскручивает буквально стек. Ну, как вот exception в Джаве более

45:19

Speaker A

формально. Что она делает, я расскажу ещё чуть позже, но пока на таком уровне хватит. Вот давайте обсудим, как панику ловить. Вот здесь есть формально, что происходит с паникой. То есть когда у нас выполняется какая-то функция f выполнение функции f, а явный вызов

45:35

Speaker A

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

45:50

Speaker A

понятно вот то, что здесь написано: explicit call to panic or run time panic turnates. Вот explicit - это вот так, понятно? Явно иначе какая-то паника, ну, допустим, или мы берём, обращаемся там, а, понятно, к какому-нибудь индексу. Так вот, понятно. То есть у нас out of about

46:04

Speaker A

b about exception, неважно. Вот, значит, что происходит? У нас функция f, она прекращает своё выполнение, но есть некоторые гарантии. Первая гарантия, что любые любые функции, которые вот в дефёре прописаны, они выполняются. То есть вот всё, что все дефёры, они

46:19

Speaker A

работают, как работали. Им не важно, как функция завершилась. Паникой, без паники, дефёры сработают. При этом понятное дело, что дефёры сработают, которые объявлены до, а не после. Те, которые после, очевидно, не будут работать. Вот. Хотя не очень очевидно, на самом деле, но они не будут работать.

46:33

Speaker A

То есть сперва у нас все дефёры выполняются. Вот. Дальше после всех дефёров у нас выполняются все дефёры функции, которые нас вызывали. То есть мы как бы идём по цепочке вверх и вызываем дифёры всех функций, которые нас вызывали. Вот если у нас мы дошли до

46:49

Speaker A

того, что мы как бы дошли дотфункции, которая нас вызвала, и не смогли, ну, на самом деле не дороф функции, а до объявления грутины. То есть на самом деле main - это ладно, мы ещё про рутине не говорили, но в общем идейно мы дошли

47:03

Speaker A

до корня. Пока можно думать про корень, что вот это корень функции, которая вот самая main, допустим, на самом деле корень - это будет вот грутина, которая то есть отдельный как бы поток не поток, а userspace поток тоже большая тема. Ну,

47:15

Speaker A

в общем, до корня, до корня. Вот если до корня дошли, тогда, к сожалению, всё умрёт. То есть у нас вся программа рушится. Ну, то есть если мы не словили exception, то у нас вся программа, к сожалению, умирает. Вот. Значит, при

47:29

Speaker A

этом понятно, мы можем сюда передать какие-то данные вот в панику. Сейчас мы чуть позже посмотрим, как можно их использовать. Но идея такая, что паника буквально вот то же самое, как, короче, можно думать, что паника - это типа throw new exception из Jaвы, афр - это

47:43

Speaker A

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

47:55

Speaker A

будет. То есть понятно, у нас случилась паника. У нас сперва напечатался deфр вот здесь вот deфр о. Вот он deф о.

48:01

Speaker A

Потом мы пошли дальше. Вот. Вот кто нас вызывал, взяли def 2, вывели вот здесь вот. А потом вот всё, что сниже нам Runтаймime завершил исполнение, сказал, что, извините, паника, мы её не словили.

48:13

Speaker A

О'кей, как панику ловить? Смотрите, у меня есть паника. Я хочу написать какую-то функцию протект, которая будет выполнять какую-нибудь функцию G. При этом, если паника случилась, то, ну, давайте, я бы хотел, конечно, в идеале, ну, вот возвращать ошибку вот здесь. Вот

48:30

Speaker A

так, на самом деле, можно сделать. А вот, ну давай, ладно, давайте, давайте, на самом деле сделаем пофиксим. То есть я хочу сделать функцию G, чтобы даже если паника случилась, то давайте сделаем какое-нибуд своё war, а R там protect pic. Вот. И сделаем вот так

48:44

Speaker A

просто паник, неважно. Вот как это работает. Я беру, выполняю функцию G. Вот. Ну понятно. Так вот ренил. Дальше вдифре что я делаю? Если у меня То есть как понять в дефёре, что была паника?

48:57

Speaker A

Есть специальная встроенная функция recover. Вот эта билн функция, которая встроена в язык. Если эта функция вызывается, она смотрит следующее. Она проверяет, правда ли, что сейчас есть паника. Вот если она, если паники нету, то возвращается просто Нил. Если паника

49:12

Speaker A

есть, то возвращается то, что было передано в панику. Это не совсем правда для Го21.

49:18

Speaker A

Сейчас мы нюансы я расскажу чуть позже, но идейно всё просто. Типа паника летит, мы можем через recкаover её поймать и записать переменную, что было передано.

49:27

Speaker A

Вот дальше, если паника случилась, то я что хочу? Я хочу, чтобы протек возвращал ошибку. Ну вот я могу это сделать вот таким образом. Вот просто присвоить ошибку к erро. Вот это на самом деле то, что я рассказывал, единственный случай,

49:37

Speaker A

когда нам нужно писать named параметр и его менять как-то в фри. Вот это такой явный пример. Давайте FR не равно new. И возьмём, выведем асоли. Значит, всё о'кей. То есть вот если мы сейчас эту функцию запустим, то что получится?

49:52

Speaker A

Смотрите, а будет старт. То есть мы были сначала вот здесь, потом у нас вызвалась функция, она у нас что сделала?

49:59

Speaker A

Запаниковала. Мы куда пошли? Пошли вот вот в этот вот дефр, вот сюда, написали дан. Вот наш дан. Потом взяли, словили панику, присвоили в переменную erрор, которую мы возвращаем, ошибку, потому что мы не хотим панику прокинуть, мы хотим ошибку прокинуть. И потом,

50:14

Speaker A

соответственно, мы хотим, ну, напечатать какое-то значение. Понятно? На самом деле лок лучше вот так на какое-то значение напечатать. Вот. А потом в конце наш протект вернул ошибку, мы её проверили ещё раз её, значит, а, ну ладно, здесь рен должен быть вот так,

50:26

Speaker A

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

50:39

Speaker A

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

50:55

Speaker A

например, в цикле бежим, что-то делаем, и нам хочется сделать meex log, потом куча какой-то логики и в конце mutex unlock. Ну и понятно, что если у нас какие-то здесь проблемы есть, то мы хотим, конечно, если ошибка, то там

51:06

Speaker A

сделать return и не забыть, опять же, вот такая же проблема, которая была до этого, сделать unlock вот здесь, вот здесь, то есть такая же проблема, которая у нас была. Вот. И это решаются буквально тем, что иногда пишут следующий код, в котором делают mxlog,

51:20

Speaker A

def, mxlog и дальше вот то, что нужно при работе с блокировкой. Ну это, кто не знает, это вот критическая секция тоже я буду подробно об этом говорить. Вот. То есть совершенно хороший вопрос очень в точку, что, да, иногда хочется в

51:34

Speaker A

каких-то местах deф использовать вот не функции, а в целом в области видимости. Поэтому, да, это можно сделать через лямбду. К сожалению, это правда, что в такоя необходимость иногда очень нужна, поэтому, да, приходится такое городить.

51:47

Speaker A

А если функция кидает панику после срабатывает deфр, который кидает ещё одну панику, то как отвалить паники и что конкретно отловится? Это довольно такой синтетический пример. Но если у нас в дифёре ещё одна паника, мы сейчас это посмотрим чуть позже, я потом покажу

52:02

Speaker A

пример, а то она просто кидается дальше, то есть это просто прокидывается вверх снова. Как понимать, что конкретно отливается, мы тоже на это посмотрим. Но опять же, это очень плохая идея строить логику на таких вот прокидываниях. Ещё раз паники, утверждение. Вот то, что я

52:16

Speaker A

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

52:21

Speaker A

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

52:28

Speaker A

Например, при работе с рефлекшеном. Такое бывает. Значит, конкретно в том месте нельзя было каждую итерацию вызывать, так как поменяется вывод. Сейчас 192, там было бы 1 2 3 4.

52:38

Speaker A

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

52:43

Speaker A

Видимо, вопрос был про вот это, про это, что ли? А, да, я я понял вопрос. Смотри, как бы там какая история? Ну, то есть идея идея какая, условно у тебя есть какой-то цикл, который, например, берёт и открывает какие-нибуд коннекшены. Ну,

52:58

Speaker A

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

53:10

Speaker A

так не писать, но иногда людим как бы пофиг, и они просто говорят: "Ну, о'кей, закроем потом всё разом". И вот я говорю про то, что так плохо делать, потому что всё разум приводит к клику. Вот. То есть конкретно в этом примере, конечно, нет,

53:21

Speaker A

как бы это будет другое поведение. Вот правильно написал Камиль в чате. А, но в целом идейно, почему так пишут? Потому что хотят закрыть разном, допустим, все коннекты. Вот. И обычно, да, конечно, лучше так не писать и сделать, вынести,

53:33

Speaker A

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

53:47

Speaker A

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

53:54

Speaker A

Потому что понятно, вот здесь вот явно 100, а здесь может быть не 100. какое-то вот хитрое значение, которое сходу не очевидно, что происходит. И тестами это сходу тоже, понятно, отловить не очень просто. Вот давайте посмотрим конкретный пример. Смотрите, у нас будет сервер.

54:06

Speaker A

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

54:22

Speaker A

ладно, ручка - это жаргон. Есть два эндпоинта. То есть, условно, есть Telegram, вы пишете какого-нибудь своего бота, и Telegram вам шлёт запрос на вашу вот point с о том, что что-то случилось. Пока вообще неважно, что. Вот у вас есть конкретный сервер.

54:38

Speaker A

Как мы помним, у нас есть вариант, что если панику никто не ловит, то вот получается очень грустно. У нас умирает всё приложение. Давайте посмотрим на практике, что будет. То есть вот я сейчас что сделаю? Я возьму и так я

54:50

Speaker A

сделаю, а, значит, л там какой порт? Такой порт и V1 ТГ. А там пост, да?

54:58

Speaker A

Хорошо. Вот я отправляю запрос на то, что вот сделали какой-то хук, мне возвращают. О'кей. Пришли. Вот берут явно делают запрос на мой сервер. О'кей.

55:08

Speaker A

Но, как мы знаем, у нас ещё есть одна ручка, которая кидает панику. Ручка - это на жаргоне в разных местах. Это endpint, так называют. Ну, в общем, просто вот тоже будем подробно обсуждать, как бы куда приходит ваш запрос. Вот если я сделаю по аналогии

55:22

Speaker A

сейчас же самое, давайте только вместо хукка сделаем здесь так вот, то, к сожалению, мне ничего не ответит. На самом деле там будет некоторый код ошибки, но это неважно. И в коде видим панику. Паник присутствует. При этом, что важно? Важно, что у меня всё ещё не

55:38

Speaker A

умерло моё основное приложение. То есть у меня всё ещё, если я отправлю, у меня всё ещё всё живо. То есть кто-то поймал панику и не дал ей убить мой сервер. Кто это сделал? Ну давайте разберёмся, кто это сделал. На самом деле за нас поймали

55:51

Speaker A

панику и сказали, что вы там это что-то не так делаете. Мы её словили, чтобы не убить ваш сервер. А на практике, когда люди, ну, в больших компаниях там всегда пишут что-то своё. То есть опять же тот же fast http, который лучше, чем в

56:06

Speaker A

некоторых случаях лучше, чем гошная либо стандартная для некоторых задач там. Ну, понятно. То есть опять же, в смысле, когда вы автор библиотеки, вам нужно об этом задумываться. Вот здесь конкретно задумались, что вот если у нас какая-то паника случилась в хендлере, то есть вот

56:19

Speaker A

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

56:29

Speaker A

компаниях пишут свои такие обработчики, чтобы, например, если у меня случилась паника, я хочу вот не просто словить вот так вот, а я хочу, например, отлеть куда-нибудь в центре, написать какой-нибудь лог, может какой-то алёрт выкинуть. или какую-нибудь метрику отлить. То есть

56:43

Speaker A

много действий я хочу сделать, что у меня случилась паника. Поэтому иногда в компаниях пишут свои, называют ещё их midleвари, а ещё называют это вот в сервенах HT 100 HTTP, это не очень корректно говорить. Вот в сервенах ещё не говорили про reser RPC. В общем,

57:00

Speaker A

это называют либо midleвари, midleware, либо интерцепторы, типа перехватчики. То есть это некоторые враперы, которые берут и оборачивают ваши эндпоинты, чтобы что-то сделать. Либо там какие-то авторизационные хедеры прокинуть, либо панику словить, либо залогировать что-то. То есть такие вот обёрточки над

57:16

Speaker A

вашими эндпоинтами. Кто не понял, опять же, не волнуйтесь, будут отдельно большие задания и занятия про то, как писать свои приложения и вот это всё. Но вот идейно важно понять, что Recover - это не какая-то игрущная штука. Её реально используют, чтобы вот когда

57:29

Speaker A

какой-то нижележащий код кидает панику, её словить. Вот. Ну и понятно, это обобщается на вот понятие конкретно сервера и медлавари. Вот тут не очень, правда, корректный шатдаун написан. Ну ладно, нормально сойдёт. Давайте пойдём дальше. Итого, понятно, у нас есть,

57:43

Speaker A

когда мы пишем свой какой-то сервер на GO, нас стандартная библиотека берёт и обезопашивает тем, что если у нас вдруг случилась паника в нашем хендлере, у нас не умирает весь сервер, потому что за нас словили эту панику. Вот это удобно,

57:54

Speaker A

что нам не нужно об этом самим думать. О'кей. Паники в рантайме. Смотрите, в стандарте есть такая весёлая штука, называется она Rime Pics. О чём эта история? То есть, например, у нас есть различные паники, которые можешь выкинуть сам рантай. Ну, например,

58:11

Speaker A

банальное деление на ноль. То есть нам выкинут панику. И утверждается, что у нас вот ратайме есть понятно своей паники. То есть это как бы в целом очевидно. И в го такой мем, что у паник рантайма есть свой специально метод.

58:27

Speaker A

Называется он runtime error. Это вот no function, которая говорит о том, что вот мы хотим различать обычные ошибки от ошибоктайма. И вот, например, можно глянуть, что вот у нас есть, допустим, в рантайме какая-нибудь error addressing string какой-нибудь, да, или

58:39

Speaker A

какой-нибудь там, опять же, вот то, что сейчас посмотрим, то, что есть небольшой такой мем со стандартной реальной жизнью. То есть утверждается, что у нас, в общем, паника имеет такой метод. При этом стандарт говорит, что Rime error они как bified. То есть вот с одной

58:54

Speaker A

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

59:08

Speaker A

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

59:18

Speaker A

бы не надо. не работает. На практике, допустим, в рантайме есть буквально публичные ошибки. То есть вот можно прямо взять и увидеть такую публичную ошибку паниклorр или публичная ошибка Type assertion error. Это вот в рефлекшене, то есть там пакет

59:32

Speaker A

reflection, который позволяет рефлексию го использовать. Он кидает под капотом такую ошибку. Допустим, когда мы пытаемся вот так вот скастить и у нас проблема, мы, ну, если мы напишем вот так вот каст без ока, то у нас вот такая

59:43

Speaker A

ошибка будет выкинута. И на самом деле нам никто не мешает её словить. То есть мы сейчас увидим чуть позже. Нам никто не мешает словить панику и закастить значение вот такую ошибку. Вот. И нам никто не мешает проверять, что у ошибки

59:54

Speaker A

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

60:08

Speaker A

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

60:18

Speaker A

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

60:31

Speaker A

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

60:46

Speaker A

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

61:03

Speaker A

если в проекте надо кому-то как-то это кэтчить, вот, то, да, там люди используют name и вот это всё есть. Даже готовые пакеты на эту всю историю с парочкой звёзд на Гитхабе. смотрел. Ну, то есть такая необходимость у людей

61:16

Speaker A

есть, но это не часто нужно. Пожалуйста, так не делайте, если это вам не надо.

61:19

Speaker A

Вот. О'кей. Да, тут на самом деле примерчик, который я уже показал. А помните, я рассказывал, что вот можно в дефёре обращаться к именованным возвращаемым значением. Вот это надо, когда опять же у вас есть какая-то паника и вы что хотите сделать? Вы

61:35

Speaker A

хотите взять вот если мы сделаем а равно b вот здесь передадим здесь нолик то понятно давайте при запуске у нас здесь выведется что понятно у нас вот на этом этапе будет паника она вот здесь в дефёре её recкаoverм словим проверим что

61:49

Speaker A

о'кей да это паника через type switch возьмём поймём что случилось вот на самом деле здесь да не очень не очень вербозно как бы отличие новажно вот и более того можно даже без теп свича чуть попроще но это как бы короче как бы

62:04

Speaker A

понятно Так, вы уже узнаете, как кастить и как проверять. Поэтому тут, допустим, вот поэтому опять же то, что я хотел сказать, вот обращаться в дефёре к именовным параметрам и что-то менять надо ровно в одном случае, когда вам надо как-то поменять ошибку из-за того,

62:20

Speaker A

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

62:33

Speaker A

раскинуты раскинуты паники. То есть там так сделать, то вот этих паник там 144 во всём пакете. То есть их там очень много. Вот видите, там повсюду просто паники раскиданы. И иногда, когда с рефлексией работаешь, ну, приходится вот так писать. То есть словил панику, её

62:46

Speaker A

аккуратненько в ошибочку завернул и прокинул дальше. То есть это единственный случай, когда надо использовать изменения напараметров дефолт. Вот. Вот, ну, здесь понятно, сставили панику, вернули здесь ошибочку, вот её вывели и всё хорошо. Вот примечание лучше использовать, конечно, не FMT в ошибках, аprint, потому что он

63:02

Speaker A

пишет в stde. Логер лучше, чем обычный fpint. Мы будем подробно ещё обсуждать, какие есть логеры. Вот будем использовать slog пока что, потом будем использовать zap. Такой логер используют часто в больших проектах. Ну, не в не в однофайловых примерах. О'кей. Ходим к

63:19

Speaker A

интересному. Давайте напишем тракетчиногу. То есть, конечно, при желании, давайте, типа, в общем, обсудим. То есть в чём концептуальная проблема паники? Проблема паники в следующем. Как мы помним из прошлого занятия прослер, когда мы кидаем панику, что происходит? У нас раскручивается

63:37

Speaker A

стек. То есть у нас, понятно, мы берём вот текущей функции, смотрим, кто её вызвал. Через адрес возврата попадаем, понятно, кто её вызывал и так далее по цепочке. Это называют традиционноваer, то есть код, который раскручивает стек, называют анвайндером. И, соответственно,

63:53

Speaker A

это медленно. Насколько медленно мы сейчас увидим, но утверждается, что это медленно. Вот условно в Джаве почему говорят, что не надо делать управление на исключениях. Ну, потому что это плохой код, а во-вторых, это медленно. А то же самое в C++. То есть когда мы

64:06

Speaker A

постоянно прокидываем туда-сюда эти ошибки несчастные, то, ну, у нас работает медленно. Это не мешает писать людям такой код, поверьте. Такое встречается. Вот. Ну, как бы я не говорю, что это как бы прямо такие такие-то плохие програмисты, но бывает

64:17

Speaker A

такое, что, да, какое-то МВП решение пишут, какой-то проект, и там как бы неважно, какой код, главное быстрее заходить. Поэтому я это понимаю. Ну, в целом такое лучше не делать, конечно.

64:25

Speaker A

Вот. Э, поэтому как можно написать свой кеч на го? Давайте сделаем функцию finли блок, как в Джаве, и вот как будет работать. Ну, понятно. Вызываем функцию в diffреем, если finally блок есть, потом его вызываем. Иначе что делаем?

64:42

Speaker A

пытаемся словить панику. Вот. Ну, вызываем, в смысле после, то есть как бы тут, если finally блок есть, вызовем его уже после вот этого всего блока. Дальше, если у нас есть паника, вот, ну, внезапно, то давайте её как бы всё

64:55

Speaker A

словим. Вот в конце, если панику прокинет какой-то изкетчеров, её прокинем дальше. То, что спрашивали, если в дефёр, в дефёре будет паника, тот если этот код что делает? Если кто-то из скетчеров ошибки нет панику, мы её прокинем дальше. Вот такой вот код. И на

65:10

Speaker A

самом деле можно было бы его, наверное, ать, ну это, в общем, ладно, пускай будет. Тут просто, видите, то тонкий момент, что тут какое-то может быть логирование, ещё что-то. То есть тут надо смотреть, но это неважно как бы.

65:21

Speaker A

Идея такая, что вызывается функция, дальше finally блок прокидывается вот как бы фёр в дефёре. Дальше мы смотрим, если есть паника, ловим. Вот. И проходимся по всем кетчерам и вызываем какой-то кетчер. Если мы смогли ошибку словить, тогда просто делаем ретрн, всё

65:35

Speaker A

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

65:44

Speaker A

Здесь как бы что есть, то есть. Вот как выглядит кечер. Ну, понятно. Catchблок - это просто параметризированная штука, которая пытается посмотреть. Если паника была кинута с таким-то типом, то тогда кастим и вызываем. Иначе возвращаем флS не смогли вызвать. Вот. И как выглядит

66:00

Speaker A

код в таком вот такой парадигме? Не надо так писать на го. Берём вызываем нашу функцию, которая кидает панику. Допустим, давайте какой-нибудь йв. Вот. Дальше у нас есть finally блок, который что-то делает. Естьч, который работает с ошибками и кетч, который

66:14

Speaker A

работает с строчками. Если мы вызовем так, то у нас что будет? У нас вызовется старт вот здесь. Потом у нас будет вот здесь, но вызовется вот этот, он отработает успешно, потому что типа error. OR. Дальше здесь вызовется этот

66:28

Speaker A

if. Сюда провалимся, будет всё о'кей. Делаем return. Вот. И потом finли блок вызывается в конце. Вот мы его здесь объявили. То же самое можно сделать, понятно, с строчкой. Вместо ошибки какую-то строчку, допустим, вернуть просто, да, можно тоже это сделать. И

66:44

Speaker A

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

66:50

Speaker A

И вызываем дальше кетчер вот этот вот здесь успешно у нас работает. Словили строчку и блокфйнере. То есть при желании, конечно, можно сделать там тракетчи, как в Джаве. Вот. Но, пожалуйста, на го так писать не надо.

67:00

Speaker A

Хотя я видел людей, которые так на го обрабатывали ошибки. Зачем так делали? Это отдельный вопрос, это как бы трейдофы, которые надо понимать. Ну там просто были некоторые пайплайны, то есть ошибки. То есть если ошибки часто случаются, то тогда такой код валите на

67:14

Speaker A

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

67:24

Speaker A

две ошибки, три-четыре ошибки, не надо. То есть есть всякие доклады и мнение людей про то, как нужно обрываться ошибки, когда их очень много. И это один из способов, это можно делать. Но важно понимать, что если у вас меньше там 15

67:38

Speaker A

ошибок, так не надо писать. Вот почему опять же в плане скорости, давайте рассмотрим такую историю. Я написал бенчмарк. Что этот бенчмарк делает?

67:46

Speaker A

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

67:56

Speaker A

Вызывается некоторые до компьютера что-то делает, какая-то функция. Вот есть два случая. Первый случай - это мы берём аккуратненько возвращаем ошибочку.

68:03

Speaker A

Вот. То есть вот здесь вот всё. Ну, то есть просто обычный goayй. Есть второй случай, это когда мы берём и кидаем панику. То есть у нас есть обычный, ну, то есть используем нашу, короче, конструкцию с печами. Вот, да, у нас есть здесь,

68:19

Speaker A

понятно, наш трай finли. Вот. И мы передаём наши два кетчера. Вот они сверху объявлены вот эти. Вот. И дальше что происходит? Ну, понятно. Дальше есть бенчмарки с успешным выполнением, без ошибки и без паники. Вот здесь. И есть бенчмарки с фейлом. То есть бенчмарк,

68:38

Speaker A

который с ошибкой и бенчмарк, который с паникой внутри. Вот если мы запустим бенчмарки, что мы видим? Вот видно, что когда у нас нет паники и нет ошибки, то в целом различий не очень много вот в нашей конструкциях. Вот. Но при этом,

68:50

Speaker A

если паника всё-таки есть, то у нас различие огромное. Вот в этом, видите, вот здесь вот обычная ошибка, а здесь случай с паника. Вот. И опять же важно понимать, что как бы если мы уж пишем такую конструкцию, то, наверное, мы

69:05

Speaker A

всё-таки рассчитываем, что у нас будет много паник. Вот можно написать такую конструкцию при желании с именно что с ошибками. То есть давайте типа идея, что идея такая, что у нас есть какие-то параметризированные хендлеры, которые мы вызываем в зависимости от типа. Вот если

69:16

Speaker A

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

69:30

Speaker A

бнчмаркете зависит от данных и от нагрузки. Вот поэтому здесь надо смотреть в любом случае. Но вот знаете, что как бы эта штука работает медленнее.

69:37

Speaker A

Почему медленнее, опять же, да, не рассказал, давайте расскажу. Когда происходит паника, опять же, я уже сказал, авадер происходит, да, я упоминал об этом уже. И стек раскручивается. Вот раскрутка стека - это недешёвое удовольствие. То есть раскрутка стека - это медленно. Поэтому,

69:50

Speaker A

ну, понятно, нужно пойти по адресам возврата, передвинуть программкатер, посмотреть на куда перейти дальше. То есть нам нужно много индирекций сделать различных. Ну, понятно, в случае стека у нас тут есть функция какая-то asкфрейм, у нас тут есть дальше какие какие-то

70:04

Speaker A

данные, дальше Bкфрейм и так далее. Вот нам нужно пройти вот отсюда сюда и вот так вот пройтись по ссылочкам. О'кей? То есть, резюмируя, в Go можно написать свой тракеч, используя recкары и паники.

70:16

Speaker A

Это, ну, не надо, как бы, это надо, когда у вас прямо конкретная какая-то ситуация, где куча паник в коде. Вот почти никогда такое не нужно. Такую же конструкцию можно поскелить на обычные ошибки. Опять же, это нужно, когда у вас

70:25

Speaker A

их очень много. Это вот один из таких типа дизайнов обработки ошибок. То есть при желании можно, конечно, такое сделать. А добре ли такое горазработчики?

70:33

Speaker A

Ну, опять же, есть люди, которые считают, что норм, есть, которые считают, что это не норм. зависит от проекта, как я уже сказал, то есть в разных компаниях, в разных проектах, в разных командах используют совершенно разные подходы, потому что, ну, у вас

70:44

Speaker A

буквально, может быть, какой-нибудь там в команде человек, который был там изначально, какие-то технологии ввёл, и все остальные пишут по аналогии. Как бы это частая история. Вот поэтому важно понять, что такой подход существует.

70:54

Speaker A

Писать так не надо. Вот просто знаете, что вот это можно сделать по-нормальному. Сейчас я покажу, как делась. То есть именно в конце я покажу вот как на практике чаще всего это будет работать и как это люди используют. Вот.

71:05

Speaker A

Давайте ещё небольшой тонкий момент. Момент тонкий в следующем. Что будет, если мы вызовем панику от нела? Вот до го121 у нас вот такая вот конструкция выводила бы вот эту строчку, что у нас паникал. То есть до го до 121 не умели различать Нил вот

71:26

Speaker A

здесь вот и Нил, что паники нет. Вот в go 121 добавили всё-таки небольшое дополнение. Теперь у нас, если мы вот так вот отдаём, то у нас вот это вот R, и это на самом деле будет под капотом вот такая структурка. Мотаем паниклорор.

71:41

Speaker A

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

71:56

Speaker A

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

72:01

Speaker A

Вот. И да, итого как бы если вызывается паника с нелом, что очень странно, у вас будет вот такая структурка под капотом, и будет корректно вызовена вот эта строчка до годни 21, к сожалению, будет просто Нил. Вы не поймёте, паника или не

72:15

Speaker A

паника, что случилось, будет просто вот это выведено. Вот это такой небольшой тонкий момент. О'кей. И крайний на сегодня пример то, как в реальной жизни работает обработка ошибок. То есть я показал разные примеры, различные парадигмы. А, то есть в реальной жизни

72:30

Speaker A

это будет следующим образом работать. У вас будет, как я уже сказал, мы будем рассматривать подробно, как писать своё приложение с различными слоями, там вся почистить архитуры, вот это всё это пока, то есть мы опустили, но по жизни это будет работать следующим образом. Вы

72:42

Speaker A

вызываете какой-то код, он под капотом, понятно, какие-то ошибки генерит. Обычно есть разделение, то есть словно ошибки уровня базы данных, ошибки уровня репозитория, ошибки уровня бизнес-логики, ошибки уровня уровня опишки. И потом у вас более высокий уровень вашего кода могут

72:57

Speaker A

проверять, правда ли, что такая ошибка случилась. Эти ошибки либо могут мапить одни в другие, либо не мапить. Зависит от проекта, от команд, как я уже сказал.

73:04

Speaker A

То есть в разных проектах, командах разные подходы. То есть обычно как бы все придерживаются каким-то, ну, стандартным радигом, что вот заворачиваем ошибки вот так вот.

73:13

Speaker A

Используем пакет errors, то есть вот и s - это очень частые вообще функции, которые постоянно вызываются. Вот. И вы просто на верхних уровнях будете эти ошибки обрабатывать и что-то с ними делать. Опять же, как я уже сказал, ловить паники, работать с паниками редко

73:27

Speaker A

приходится. Вот обычно это вот такой код, который просто вот вызывает какие-то функции, они возвращают ошибки, мы их как-то хендлим и какую-то логику делаем. Вот, допустим, как здесь там file not found, либо там пермишенов не хватило, либо там й нов, понятно

73:40

Speaker A

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

73:52

Speaker A

сегодня, но вот в реальности вот обычный кошный код - это вот просто вызов каких-то функции, обработка ошибок через errors из, возможно, через errors как раз-таки s получение инстаса ошибки и там получение каких-то полей из этой ошибки. Почему нет? То есть понятно, S

74:08

Speaker A

говорит, правда ли, что ошибка была, а S позволяет закастить явно в эту ошибку. Вот.

74:13

Speaker A

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

74:22

Speaker A

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

74:36

Speaker A

то есть в коде, который связан с доминологикой, есть буквально состояние паник. Ну вот люди так живут. Это неплохо, на самом деле. То есть, ну, если в рамках логики такое состояние валидно, то есть какое-то техническое состояние, то почему нет? Но, конечно,

74:49

Speaker A

как я сказал, всегда нужно смотреть этот проект, отталкиваться и понимать, на что вы идёте. Спасибо большое за просмотр.

74:55

Speaker A

Переходи в мой Telegram-канал, чтобы оставаться на связи, и пиши в комментариях, какая часть из видео тебе понравилась больше всего.

Topics: Go Golang обработка ошибок error паника recover интерфейсы собеседование Go errors.Is errors.As

Учить по этому видео

- [Карточки по этому видео](https://sozai.app/ru/tools/flashcard-maker/?from=transcript&id=94304)
- [Тест по этому видео](https://sozai.app/ru/tools/quiz-generator/?from=transcript&id=94304)
- [Кроссворд по этому видео](https://sozai.app/ru/tools/crossword-maker/?from=transcript&id=94304)
- [Филворд по этому видео](https://sozai.app/ru/tools/word-search-maker/?from=transcript&id=94304)
- [Шпаргалка по этому видео](https://sozai.app/ru/tools/study-guide-maker/?from=transcript&id=94304)

Бесплатно, составлено ИИ по этой расшифровке. Без регистрации.


---
This is the markdown twin of https://sozai.app/transcript/common-go-mistakes-complete-guide-interviews/ — the same content, without the markup.
Published by SozAI (https://sozai.app). Reuse and quotation are allowed with attribution and a link back.
Machine-readable index: https://sozai.app/llms.txt · data API: https://sozai.app/api/
