Ошибки, defer, panic, recover¶
error¶
В Go ошибка — это значение, реализующее интерфейс:
Каноничная сигнатура: func Foo() (Result, error).
%w — wrapping, нужен для errors.Is / errors.As:
Sentinel и typed errors¶
// Sentinel — заранее объявленное значение
var ErrNotFound = errors.New("not found")
// Typed error — структура с дополнительным контекстом
type ValidationError struct {
Field string
Msg string
}
func (e *ValidationError) Error() string { return e.Field + ": " + e.Msg }
Sentinel сравниваем через errors.Is, typed — через errors.As.
defer¶
file, err := os.Open(path)
if err != nil { return err }
defer file.Close() // выполнится при выходе из функции
Свойства defer:
- LIFO порядок (стек).
- Аргументы вычисляются в момент defer, тело — в момент выхода.
- Гарантированно выполняется при panic'е (что даёт recover).
defer-гочча: аргументы вычисляются сразу¶
Если хочешь актуальное значение — используй замыкание:
panic / recover¶
panic останавливает выполнение и раскручивает стек. recover ловит её
только внутри deferred функции:
func safeDivide(a, b int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("panic: %v", r)
}
}()
return a / b, nil // panic при b==0
}
Когда уместно использовать panic: - programmer error (assertion, неконсистентное состояние); - невосстановимое состояние (отказ инициализации).
Для бизнес-ошибок — всегда error. panic в публичном API — плохой тон.
📖 Связанные задачи: must-solve-100 → C-006..C-008.