Уроки модуля (5/5)
Интерфейс ошибки
error в Go — это не ключевое слово: это встроенный интерфейс с
единый метод.
type error interface {
Error() string
}Все, что имеет Error() string, является error. В сочетании с
соглашение о возврате (T, error) из функций, это
основы обработки ошибок в Go.
Дозорные ошибки
import "errors"
var ErrNotFound = errors.New("non trovato")
func find(key string) (string, error) {
// ...
return "", ErrNotFound
}Sentinel — это экспортированное значение error, которое вызывающая сторона может
сравнить, чтобы распознать конкретный случай ошибки.
Пользовательские ошибки (с данными)
Для переноса контекста (например, отсутствующего ключа) вы определяете тип:
type ErrNotFound struct {
Key string
}
func (e *ErrNotFound) Error() string {
return "non trovato: " + e.Key
}
func find(key string) (string, error) {
return "", &ErrNotFound{Key: key}
}ошибки.Есть и ошибки.Как (Go 1.13+)
Сравнение с == работает только для «чистых» дозорных. Быть надежным
против завернутых ошибок используйте пакет errors:
import "errors"
if errors.Is(err, ErrNotFound) {
// err IS ErrNotFound (even if wrapped)
}
var nfe *ErrNotFound
if errors.As(err, &nfe) {
// err IS (or wraps) an *ErrNotFound; nfe points to the concrete value
fmt.Println("chiave mancante:", nfe.Key)
}errors.Is(err, target): true, если цель находится где-то в цепочке упаковки.errors.As(err, &target): назначает целью первую ошибку в цепочке ее типа.
Обертывание с помощью %w
if err := find("k"); err != nil {
return fmt.Errorf("operazione X: %w", err)
}%w (НЕ %s или %v) создает новую ошибку, которая переворачивает
оригинал, сохраняя возможность навигации по цепочке для errors.Is/As.
Схема обработки
v, err := op()
if err != nil {
return fmt.Errorf("op fallita per %q: %w", id, err)
}Идиомы:
- Проверьте
err != nilнемедленно, никакого «раннего счастливого пути». - Добавьте контекст на каждом уровне с помощью
fmt.Errorf("... : %w", err). - «Вверх по течению» (рядом с основным/обработчиком), различать с помощью
errors.Is/As.
Попробуйте это
Реализуйте строку Error() для *ErrNotFound, чтобы она возвращала «non trovato: <Key>».
Показать подсказку
`fmt.Println(err)` автоматически вызывает метод Error() в вашей структуре.
Решение доступно после 3 попыток
Используйте ошибки. Чтобы проверить, соответствует ли err дозорному ErrVuoto.
Показать подсказку
`errors.Is(err, target)` надежен даже с цепочками-обертками.
Решение доступно после 3 попыток
Какова точная сигнатура метода реализации ошибки?
func (e *MyErr) ??? {}Резюме
error = interface { Error() string }, встроенный.- Стражи с
errors.New("...")для известных случаев без контекста. - Пользовательские типы ошибок с полями для передачи контекста.
errors.Is(err, target): сравнение устойчиво к переносу.errors.As(err, &target): извлечение типа бетона.fmt.Errorf("...: %w", err): упаковка, сохраняющая цепочку.- Никогда не используйте
%v/%sдля переноса: ВСЕГДА используйте%w.