Перехват останова в Go
Останов можно перехватить и продолжить программу
со следующей строки вызывающего кода. Для
этого в отложенной функции вызывают recover:
пока идет размотка стека, она возвращает
значение, которое передали при останове, и
снимает панику.
После успешного перехвата выполнение не возвращается в хвост функции, где сработал останов. Управление появляется сразу после вызова этой функции у того, кто ее вызвал.
Соберем перехват в main и посмотрим
на порядок строк:
package main
import "fmt"
func work() {
fmt.Println("inside")
panic("fail")
fmt.Println("tail")
}
func main() {
defer func() {
if msg := recover(); msg != nil {
fmt.Println("caught")
}
}()
work()
fmt.Println("main line")
}
На экране по очереди "inside",
"caught" и "main line".
Строка "tail" не печатается: после
останова тело work уже не продолжается.
Зато "main line" выполняется, потому
что перехват вернул управление в main
сразу после вызова work.
Тот же прием можно обернуть в отдельную функцию, чтобы не дублировать отложенный блок:
package main
import "fmt"
func safeRun(fn func()) {
defer func() {
if msg := recover(); msg != nil {
fmt.Println("ok")
}
}()
fn()
}
func main() {
safeRun(func() {
panic("x")
})
fmt.Println("next")
}
Дана функция:
func step() {
fmt.Println("step")
panic("err")
fmt.Println("lost")
}
В main перехватите останов из
step в отложенной функции и
выведите "after" сразу после
вызова step.
Дан следующий код:
package main
import "fmt"
func boom() {
panic("no")
}
func main() {
defer func() {
recover()
}()
boom()
fmt.Println("live")
}
Скажите, появится ли на экране "live".
Скажите, из какой функции выполнение
продолжается после перехвата останова
внутри work из первого примера
урока.