Данный код скомпилируется, но при запуске приведёт к панике, и не выведет ожидаемого результата из-за порядка вызова defer и panic.
Go: defer и recover, объявленный после panic
Данный код скомпилируется, но при запуске приведёт к панике, и не выведет ожидаемого результата из-за порядка вызова defer и panic.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
// Вопрос 2. Что выведет на экран
package main
import "fmt"
func main() { { defer fmt.Println(1) } defer fmt.Println(2)
panic("aaaa")
defer func(){
if r := recover(); r != nil{
fmt.Println("Паника обработана", r)
}
}()
}
Ответ
Данный код скомпилируется, но при запуске приведёт к панике, и не выведет ожидаемого результата из-за порядка вызова defer и panic.
Разбор:
- Внутри блока
{ defer fmt.Println(1) }отложен вывод1. - Затем отложен вывод
2. - Затем вызывается
panic("aaaa"). - После panic вызывается последний defer с функцией, которая пытается сделать recover.
Однако, в Go defer-выражения выполняются в обратном порядке их объявления при выходе из функции, включая выход из-за panic.
Порядок выполнения defer при panic:
- Выполняется последний defer — функция с recover.
- Если recover срабатывает, паника прекращается, и программа продолжает выполнение.
- Затем выполняются остальные defer —
fmt.Println(2)иfmt.Println(1).
Но в данном коде defer с recover объявлен после panic, то есть он не будет вызван, так как panic прерывает выполнение сразу.
На самом деле, код не скомпилируется, потому что после panic идут defer, что недопустимо — panic прерывает выполнение, и последующий код не выполняется.
Если бы defer с recover был объявлен до panic, то вывод был бы:
Паника обработана aaaa
2
1
Итог: в текущем виде код вызовет panic и завершится с ошибкой, не выведя ничего, так как defer с recover объявлен после panic и не сработает.