Go: вместо исключений

Одна из вещей, которыми привлекателен go - "декомпозиция" "сложных" конструкций в более элементарные. Что и семантику проясняе и повышает гибкость. Ну так вот в Go нет exceptions.

Вместо них есть три встроенные функции/оператора:

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 это несколько через жопу и автогеном