Почему `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")
}
Ответы
Ответ 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()
от этого останавливает последовательность панорамирования.