Подтвердить что ты не робот

Почему `defer recover()` не ловить паники?

Почему вызов defer func() { recover() }() успешно восстанавливает пародию goroutine, но вызов defer recover() not?

В качестве минималистического примера этот код не паникует

package main

func main() {
    defer func() { recover() }()
    panic("panic")
}

Однако, заменив анонимную функцию на восстановление непосредственно паники

package main

func main() {
    defer recover()
    panic("panic")
}
4b9b3361

Ответ 1

В разделе Обработка паники упоминается, что

Две встроенные функции, panic и recover, помогают сообщать и обрабатывать паники во время выполнения

Функция recover позволяет программе управлять поведением паникой goroutine.

Предположим, что функция G отбрасывает функцию D, которая вызывает recover, а panic встречается в функции того же goroutine, в которой выполняется G.

Когда выполнение отложенных функций достигает D, возвращаемое значение D вызывает recover будет значением, переданным вызову паники.
Если D возвращается нормально, не начиная новую панику, последовательность паники останавливается.

Это иллюстрирует, что recover предполагается вызывать в отложенной функции, а не напрямую.
Когда это панически, "отложенная функция" не может быть встроенной recover(), а одной из них указана в заявлении defer.

DeferStmt = "defer" Expression .

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

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

Ответ 2

Цитата из документации встроенной функции recover():

Если восстановление вызвано вне, отложенная функция будет не останавливать паникующую последовательность.

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

Если recover() вызовет recover() сам по себе, он остановит последовательность паники (но зачем это делать?).

Еще один интересный пример:

Следующий код также не паникует (попробуйте на Перейти на игровой площадке):

package main

func main() {
    var recover = func() { recover() }
    defer recover()
    panic("panic")
}

Здесь мы создаем переменную recover типа функции, которая имеет значение анонимной функции, вызывающей встроенную функцию recover(). И мы указываем, что значение переменной recover должно быть отложенной функцией, поэтому вызов встроенного recover() от этого останавливает последовательность панорамирования.