← Назад к вопросам

Какой интерфейс у Error?

2.0 Middle🔥 162 комментариев
#Основы Go

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Интерфейс error в Go

В Go интерфейс error является, пожалуй, самым важным встроенным интерфейсом. Его определение крайне простое, но эта простота скрывает глубокую философию обработки ошибок, характерную для языка.

Определение интерфейса

type error interface {
    Error() string
}

Как видите, интерфейс содержит всего один метод Error(), который возвращает строковое описание ошибки. Любой тип, реализующий этот метод, автоматически удовлетворяет интерфейсу error.

Стандартная реализация error

В пакете errors предоставляется стандартная реализация:

package errors

func New(text string) error {
    return &errorString{text}
}

type errorString struct {
    s string
}

func (e *errorString) Error() string {
    return e.s
}

Создание ошибок

1. Простые ошибки

import "errors"

func Divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("division by zero")
    }
    return a / b, nil
}

2. Форматированные ошибки (Go 1.13+)

import "fmt"

func ProcessFile(path string) error {
    // Симуляция ошибки
    return fmt.Errorf("failed to process file %s: %w", path, ErrFileCorrupted)
}

Расширенная функциональность (Go 1.13+)

Начиная с Go 1.13, ошибки получили дополнительные возможности через функции в пакете errors:

1. Обертки ошибок (error wrapping)

var baseErr = errors.New("base error")

func doSomething() error {
    return fmt.Errorf("operation failed: %w", baseErr)
}

func main() {
    err := doSomething()
    
    // Проверка на конкретную ошибку
    if errors.Is(err, baseErr) {
        fmt.Println("Это наша базовая ошибка!")
    }
}

2. Извлечение обернутой ошибки

type PathError struct {
    Path string
    Err  error
}

func (e *PathError) Error() string {
    return fmt.Sprintf("path %s: %v", e.Path, e.Err)
}

func main() {
    err := &PathError{
        Path: "/etc/passwd",
        Err:  os.ErrPermission,
    }
    
    // Извлечение конкретного типа ошибки
    var pathErr *PathError
    if errors.As(err, &pathErr) {
        fmt.Printf("Ошибка доступа к пути: %s\n", pathErr.Path)
    }
}

Лучшие практики работы с ошибками

1. Всегда проверяйте ошибки

// ПЛОХО - игнорирование ошибки
file, _ := os.Open("file.txt")

// ХОРОШО - явная проверка
file, err := os.Open("file.txt")
if err != nil {
    // Обработка ошибки
    return fmt.Errorf("open file: %w", err)
}

2. Добавляйте контекст к ошибкам

func ReadConfig(path string) (*Config, error) {
    data, err := os.ReadFile(path)
    if err != nil {
        return nil, fmt.Errorf("read config %s: %w", path, err)
    }
    
    var config Config
    if err := json.Unmarshal(data, &config); err != nil {
        return nil, fmt.Errorf("parse config %s: %w", path, err)
    }
    
    return &config, nil
}

3. Создавайте собственные типы ошибок для сложных сценариев

type ValidationError struct {
    Field   string
    Message string
}

func (e ValidationError) Error() string {
    return fmt.Sprintf("validation error on field %s: %s", e.Field, e.Message)
}

func (e ValidationError) Unwrap() error {
    return nil
}

Полезные функции для работы с ошибками

import (
    "errors"
    "fmt"
)

func main() {
    err := someOperation()
    
    // Проверка на конкретную ошибку
    if errors.Is(err, io.EOF) {
        // Обработка конца файла
    }
    
    // Проверка на соответствие типу
    var sysErr *os.SyscallError
    if errors.As(err, &sysErr) {
        // Работа с SyscallError
    }
    
    // Получение цепочки ошибок
    fmt.Printf("%+v\n", err) // Поддержка формата %+v в некоторых библиотеках
}

Почему такой простой интерфейс?

Простота интерфейса error имеет несколько важных преимуществ:

  1. Универсальность - любой тип может стать ошибкой
  2. Простота использования - минимальный порог вхождения
  3. Гибкость - возможность создавать сложные иерархии ошибок
  4. Производительность - нет накладных расходов на рефлексию

Сравнение с исключениями в других языках

В отличие от исключений в Java или C++, ошибки в Go:

  • Явные - функция явно возвращает ошибку
  • Часть сигнатуры - ошибки входят в возвращаемые значения
  • Не прерывают выполнение - нет неявного propagation
  • Легко отслеживаемые - стек вызовов сохраняется в контексте

Интерфейс error в Go воплощает философию языка: простые, композируемые абстракции, которые при правильном использовании дают мощные возможности. Хотя он состоит всего из одного метода, в сочетании с идиомами Go и современными практиками (обертки, errors.Is/As), он образует полноценную, эффективную систему обработки ошибок.

Какой интерфейс у Error? | PrepBro