Несмотря на наличие
мануала непросто досконально понять, как работают конструкции panic и recover.
Наиболее понятная из двух функций — panic, она работает идентично выбрасыванию исключения: прерывает выполнение программы, собирает в свой стек все вызовы ф-ций, которые привели к директиве panic, вся эта информация будет выведена в консоль.
Обработать panic может помочь ф-ция recover. Ф-ция сама по себе бессмысленна и использоваться должна в следующем фрагменте кода:
defer func() {
if r := recover(); r != nil {
// любые действия при возникновении ошибки
}
}()
Как видим recover вызывается внутри отложенной (defer) конструкции.
Код defer вызывается при завершении ф-ции, в которой он описан. При чем вызовется он в любом случае: в случае рядового завершения ф-ции; при панике паники; в случае завершения всей программы после SIGKILL.
Recover похож на catch, но всё же не дотягивает до него, т.к. после catch можно продолжить выполнение ф-ции как угодно, например вернуть какое-то другое значение (вызвать return). Recover же даёт возможность выполнить некоторое действие, но повлиять на возвращаемое ф-цией значение уже не может, т.к. он выполняется recover в контексте defer.
Интересно, что ф-ция, внутри которой сработал defer-recover, вернёт дефолтное значение своего типа. Например, если ф-ция bool, то false. Если int, то 0. Если указатель, то nil.
Пример ниже показывает то, что ф-ция типа *string после recover вернёт nil, как бы не хотелось получить указатель на 456.
s:= func() *string {
defer func() {
if r := recover(); r != nil {
d := "456"
return &d
}
}()
panic("error");
d := "123"
return &d
}()
log.Printf("%+v\n", s) // выведет nil