Назад к урокам

Обработка ошибок в Go

Урок объясняет, как устроена обработка ошибок в Go: возврат ошибок как последнего значения, создание простых ошибок через errors.New, реализация кастомных ошибок, использование errors.Is и errors.As, а также принципы корректного проектирования ошибок.

Начинающий12 min

⚠️ Обработка ошибок в Go

Обработка ошибок - фундаментальная часть Go. В языке нет исключений, вместо этого ошибки возвращаются как последнее возвращаемое значение функций. Это делает логику ошибок явной, понятной и предсказуемой.


📌 Основные принципы

  • Ошибки возвращаются последним значением функции.
  • Если ошибки нет - возвращается nil.
  • Ошибка - это значение, реализующее интерфейс:
type error interface {
    Error() string
}

Это делает ошибки обычными значениями, с которыми можно работать.


🛠 Простые ошибки через errors.New

Стандартный пакет errors позволяет быстро создавать простые ошибки:

import "errors"

func divide(lhs, rhs int) (int, error) {
    if rhs == 0 {
        return 0, errors.New("cannot divide by zero")
    }
    return lhs / rhs, nil
}

Такой подход удобен, когда ошибка не требует сложных данных.


🧩 Создание собственных ошибок

Можно создавать собственные типы ошибок:

type DivError struct {
    a, b int
}

func (d *DivError) Error() string {
    return fmt.Sprintf("Cannot divide by zero: %d / %d", d.a, d.b)
}

Почему метод должен быть с указателем?

  • Чтобы корректно сравнивать ошибки.
  • Чтобы избежать копирования структуры ошибки.

▶️ Использование кастомной ошибки

func div(a, b int) (int, error) {
    if b == 0 {
        return 0, &DivError{a, b}
    }
    return a / b, nil
}

answer, err := div(9, 0)
if err != nil {
    fmt.Println(err)
    return
}
fmt.Println(answer)

🔍 Работа с ошибками: errors.Is

Когда нужно проверить, относится ли ошибка к определённому типу:

var inputErr = &UserError{"Input Error"}

if errors.Is(err, inputErr) {
    fmt.Println("Input error:", err)
} else {
    fmt.Println("Other error:", err)
}

errors.Is проверяет всю цепочку ошибок, включая обёртки.


🔎 Извлечение ошибки: errors.As

Когда нужно получить объект ошибки конкретного типа:

var target *UserError

if errors.As(err, &target) {
    fmt.Println("User error:", target)
} else {
    fmt.Println("Other error:", err)
}

Если ошибка соответствует типу, она будет извлечена в переменную target.


📘 Итоги

  • Ошибки возвращаются последним значением, нет исключений.
  • Простые ошибки создаются через errors.New.
  • Кастомные ошибки реализуют интерфейс error.
  • Всегда проверяйте if err != nil.
  • errors.Is - для проверки типа ошибки.
  • errors.As - для извлечения ошибки нужного типа.
Обработка ошибок в Go | WebSchool