Go: вместо исключений
Одна из вещей, которыми привлекателен go - "декомпозиция" "сложных" конструкций в более элементарные. Что и семантику проясняе и повышает гибкость. Ну так вот в Go нет exceptions.
Вместо них есть три встроенные функции/оператора:
defer задает выполнение функции, которая дана оператору аргументом при любом (нормальном и нет) выходе из функции, panic (x) соответствует логически выбрасыванию исключения x - то есть инициируется свертка стека вызовов с выполнением сопутствующих defer-ов.
recover возвращает nil если вызывается в "штатном" режиме исполения и аргумент panic если программа находится в процессе свертки стека. Собственно пример из описания языка - функция-оболочка, которая выполняет свой аргумент, отлавливая исключения и выдавая диагностику на них:
Замечу что если надо отправить исключение дальше - достаточно вызвать внутри обработчика panic еще раз, если нужна обработка "в зависимости от типа ошибки" - просто внутри defer применить switch по типу интерфейса.
В принципе вроде бы ничего особенного, но довольно громоздкая конструкция try-catch-finally разобрана на элементарные, причем тот же defer весьма полезен "отдельно от"
PS: Замечу что то что "try-catch" кривоват поняли даже в C# и придумали тоже довольно кривой оператор using, кой форсит выполнение финализатора при выходе из блока - при желании на нем кстати можно defer сэмулировать - просто заведя класс Defer, который будет хратить функцию "выхода" и выполняеть ее в финализаторе - хотя imho это несколько через жопу и автогеном
Вместо них есть три встроенные функции/оператора:
defer <function-expression>
func panic (interface {})
func recover () interface {}
defer задает выполнение функции, которая дана оператору аргументом при любом (нормальном и нет) выходе из функции, panic (x) соответствует логически выбрасыванию исключения x - то есть инициируется свертка стека вызовов с выполнением сопутствующих defer-ов.
recover возвращает nil если вызывается в "штатном" режиме исполения и аргумент panic если программа находится в процессе свертки стека. Собственно пример из описания языка - функция-оболочка, которая выполняет свой аргумент, отлавливая исключения и выдавая диагностику на них:
func protect(g func()) {
defer func() {
log.Println("done") // Println executes normally even if there is a panic
if x := recover(); x != nil {
log.Printf("run time panic: %v", x)
}
}()
log.Println("start")
g()
}Замечу что если надо отправить исключение дальше - достаточно вызвать внутри обработчика panic еще раз, если нужна обработка "в зависимости от типа ошибки" - просто внутри defer применить switch по типу интерфейса.
В принципе вроде бы ничего особенного, но довольно громоздкая конструкция try-catch-finally разобрана на элементарные, причем тот же defer весьма полезен "отдельно от"
PS: Замечу что то что "try-catch" кривоват поняли даже в C# и придумали тоже довольно кривой оператор using, кой форсит выполнение финализатора при выходе из блока - при желании на нем кстати можно defer сэмулировать - просто заведя класс Defer, который будет хратить функцию "выхода" и выполняеть ее в финализаторе - хотя imho это несколько через жопу и автогеном