Перейти к основному содержимому
Модуль 6 · Урок 5 из 530/50 в курсе~14 min
Уроки модуля (5/5)

Интерфейс ошибки

error в Go — это не ключевое слово: это встроенный интерфейс с единый метод.

Go
type error interface {
    Error() string
}

Все, что имеет Error() string, является error. В сочетании с соглашение о возврате (T, error) из функций, это основы обработки ошибок в Go.

Дозорные ошибки

Go
import "errors"

var ErrNotFound = errors.New("non trovato")

func find(key string) (string, error) {
    // ...
    return "", ErrNotFound
}

Sentinel — это экспортированное значение error, которое вызывающая сторона может сравнить, чтобы распознать конкретный случай ошибки.

Пользовательские ошибки (с данными)

Для переноса контекста (например, отсутствующего ключа) вы определяете тип:

Go
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:

Go
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

Go
if err := find("k"); err != nil {
    return fmt.Errorf("operazione X: %w", err)
}

%w (НЕ %s или %v) создает новую ошибку, которая переворачивает оригинал, сохраняя возможность навигации по цепочке для errors.Is/As.

Схема обработки

Go
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.

Попробуйте это

Упражнение#go.m6.l5.e1
Попыток: 0Загрузка…

Реализуйте строку Error() для *ErrNotFound, чтобы она возвращала «non trovato: <Key>».

Загрузка редактора…
Показать подсказку

`fmt.Println(err)` автоматически вызывает метод Error() в вашей структуре.

Решение доступно после 3 попыток

Упражнение#go.m6.l5.e2
Попыток: 0Загрузка…

Используйте ошибки. Чтобы проверить, соответствует ли err дозорному ErrVuoto.

Загрузка редактора…
Показать подсказку

`errors.Is(err, target)` надежен даже с цепочками-обертками.

Решение доступно после 3 попыток

Quiz#go.m6.l5.e3
Готово

Какова точная сигнатура метода реализации ошибки?

Go
func (e *MyErr) ??? {}
Варианты ответа

Резюме

  • error = interface { Error() string }, встроенный.
  • Стражи с errors.New("...") для известных случаев без контекста.
  • Пользовательские типы ошибок с полями для передачи контекста.
  • errors.Is(err, target): сравнение устойчиво к переносу.
  • errors.As(err, &target): извлечение типа бетона.
  • fmt.Errorf("...: %w", err): упаковка, сохраняющая цепочку.
  • Никогда не используйте %v / %s для переноса: ВСЕГДА используйте %w.