Go

Обработка ошибок: обёртки и errors.Is/As

Algonexys · 07.08.2026 · 👁 0

Идиоматичный Go: добавление контекста через %w, собственные типы ошибок и их проверка.

Код

package main

import (
	"errors"
	"fmt"
	"os"
)

var ErrNotFound = errors.New("не найдено")

// Собственный тип ошибки с дополнительными полями
type ValidationError struct {
	Field  string
	Reason string
}

func (e *ValidationError) Error() string {
	return fmt.Sprintf("поле %q: %s", e.Field, e.Reason)
}

func loadUser(id int) error {
	if id <= 0 {
		return &ValidationError{Field: "id", Reason: "должен быть положительным"}
	}
	if _, err := os.ReadFile(fmt.Sprintf("users/%d.json", id)); err != nil {
		// %w сохраняет исходную ошибку в цепочке
		return fmt.Errorf("загрузка пользователя %d: %w", id, err)
	}
	return nil
}

func main() {
	err := loadUser(42)

	// Сравнение с конкретной ошибкой по цепочке
	if errors.Is(err, os.ErrNotExist) {
		fmt.Println("файла нет:", err)
	}

	// Извлечение типизированной ошибки
	var ve *ValidationError
	if errors.As(err, &ve) {
		fmt.Println("ошибка валидации поля:", ve.Field)
	}

	// Объединение нескольких ошибок (Go 1.20+)
	combined := errors.Join(ErrNotFound, err)
	fmt.Println(errors.Is(combined, ErrNotFound)) // true
}