5.10. Основные принципы обработки ошибок в Go
Основные принципы обработки ошибок в Go
Основные принципы обработки ошибок в Go
-
Ошибки — это значения.
Типerror— это встроенный интерфейс:type error interface {
Error() string
} -
Функции возвращают ошибку как последнее значение (по соглашению):
func doSomething() (Result, error) -
Нет
try/catch,throw,raise.
Ошибки проверяются явно с помощью условного оператора:if err != nil {
// обработка ошибки
} -
Паника (
panic) существует, но не предназначена для обычной обработки ошибок.panic(v interface{})прерывает нормальное выполнение.recover()может быть вызван в отложенной функции (defer) для перехвата паники.- Используется только для некорректируемых ошибок (например, нарушение инвариантов, ошибки инициализации).
Встроенные типы ошибок
Go не предоставляет иерархии стандартных классов ошибок. Однако в стандартной библиотеке определены некоторые конкретные типы, реализующие интерфейс error:
1. errors.errorString (неэкспортируемый)
- Внутренний тип, используемый функцией
errors.New("message"). - Содержит только строковое сообщение.
2. Общие ошибки из стандартной библиотеки:
io.EOF— сигнал конца потока (не ошибка в обычном смысле).io.ErrUnexpectedEOFio.ErrNoProgressos.ErrInvalidos.ErrPermissionos.ErrExistos.ErrNotExistsyscall.Errno— системные ошибки (например,ENOENT,EACCES), которые также реализуютerror.
3. Пакет errors (начиная с Go 1.13) предоставляет поддержку:
- Оборачивания ошибок:
fmt.Errorf("...: %w", err) - Проверки цепочки ошибок:
errors.Is(err, target),errors.As(err, &target)
Это позволяет строить цепочки ошибок с контекстом, но без иерархии типов.
Паники (аварийные остановки)
Хотя паники не являются «ошибками» в обычном смысле, они могут быть вызваны встроенным кодом:
- Нарушение границ массива:
index out of range - Разыменование нулевого указателя:
invalid memory address or nil pointer dereference - Вызов метода у
nil-интерфейса - Конкурентное изменение map без мьютекса:
concurrent map writes - Переполнение стека:
stack overflow - Ошибки при разыменовании интерфейса:
interface conversion: ...
Эти ситуации вызывают panic, но не представляют собой именованные типы исключений — сообщение передаётся как строка или встроенная константа.
Нет типов ошибок
В Go нет списка «типов ошибок», аналогичного другим языкам, потому что:
- Ошибки — это значения произвольных типов, реализующих интерфейс
error. - Нет иерархии наследования.
- Нет встроенных классов вроде
IndexError,KeyErrorи т.п. - Стандартная библиотека использует семантические переменные-ошибки (
os.ErrNotExist) или динамические сообщения.
Таким образом, вместо таксономии исключений в Go применяется дисциплина явной проверки возвращаемых значений и использование контекстуальных сообщений.
Если требуется классификация ошибок, разработчик сам определяет соответствующие типы:
type ValidationError struct {
Field string
Msg string
}
func (e ValidationError) Error() string {
return fmt.Sprintf("validation failed for %s: %s", e.Field, e.Msg)
}
Такой подход обеспечивает гибкость, но отказывается от глобальной иерархии ошибок.