«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Пользовательские ошибки в Go

Пользовательские ошибки в Go

Опубликовано 8 ноября 2024 г.
Просматривать:561

Custom errors in Go

Введение

Golang или Go имеет надежный механизм обработки ошибок, который является неотъемлемой частью конструкции языка. Хотя Go предоставляет встроенные типы ошибок, существуют ситуации, когда вам может потребоваться больше контроля и контекста при обработке ошибок.
Именно здесь в игру вступает создание пользовательских ошибок. Пользовательские ошибки могут предоставить вам более информативные сообщения об ошибках и могут использоваться для классификации различных типов ошибок в вашем приложении.

В этой статье мы рассмотрим, как эффективно создавать и использовать пользовательские ошибки в Golang.

Понимание встроенной обработки ошибок Go

В Go тип ошибки представляет собой встроенный интерфейс, который выглядит следующим образом:

type error interface {
    Error() string
}

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

Базовая обработка ошибок в Go

Вот краткий пример базовой обработки ошибок в Go:

package main

import (
    "errors"
    "fmt"
)

func main() {
    err := doSomething()
    if err != nil {
        fmt.Println("Error:", err)
    }
}

func doSomething() error {
    return errors.New("something went wrong")
}

В этом примере используется функция error.New для создания базовой ошибки. Хотя это полезно для простых случаев, ему не хватает возможности предоставить больше контекста или различать разные типы ошибок.

Зачем создавать пользовательские ошибки?

Пользовательские ошибки необходимы, когда вам нужны более наглядные сообщения об ошибках или если вы хотите по-разному обрабатывать различные типы ошибок. Например, вы можете захотеть вернуть определенный тип ошибки, если файл не найден, и другой тип, если файл поврежден. Пользовательские ошибки также могут содержать дополнительные данные, что упрощает отладку и предоставляет вызывающей стороне более подробную информацию.

Создание пользовательских ошибок в Go

Чтобы создать собственную ошибку в Go, вы определяете новый тип, реализующий метод Error(). Давайте рассмотрим пример.

Пример 1: Простая пользовательская ошибка

Вот как можно создать простую пользовательскую ошибку:

package main

import (
    "fmt"
)

type MyError struct {
    Code    int
    Message string
}

func (e *MyError) Error() string {
    return fmt.Sprintf("Code %d: %s", e.Code, e.Message)
}

func main() {
    err := doSomething()
    if err != nil {
        fmt.Println("Error:", err)
    }
}

func doSomething() error {
    return &MyError{
        Code:    404,
        Message: "Resource not found",
    }
}

В этом примере MyError — это пользовательский тип ошибки, включающий код и сообщение. Метод Error() форматирует их в строку, что позволяет легко распечатать или зарегистрировать ошибку.

Пример 2: Проверка ошибок с помощью функции error.Is

Иногда полезно сравнивать ошибки напрямую. Вот тут-то и появляются дозорные ошибки. Дозорная ошибка — это предопределенная экспортированная переменная, которая представляет конкретную ошибку.

package main

import (
    "errors"
    "fmt"
)

var ErrNotFound = errors.New("resource not found")

func main() {
    err := doSomething()
    if errors.Is(err, ErrNotFound) {
        fmt.Println("Error:", err)
    }
}

func doSomething() error {
    return ErrNotFound
}

Хотя этот подход прост, объединение контрольных значений с пользовательскими типами ошибок может быть еще более эффективным, позволяя как сравнивать ошибки, так и получать расширенные данные об ошибках.

Пример 3: перенос ошибок для большего контекста

В Go 1.13 появилась функция fmt.Errorf с глаголом %w, которая позволяет оборачивать ошибки, добавляя больше контекста, сохраняя при этом исходную ошибку.

package main

import (
    "errors"
    "fmt"
)

var ErrNotFound = errors.New("resource not found")

func main() {
    err := doSomething()
    if err != nil {
        fmt.Println("Error:", err)
        if errors.Is(err, ErrNotFound) {
            fmt.Println("The resource was not found.")
        }
    }
}

func doSomething() error {
    err := fetchResource()
    if err != nil {
        return fmt.Errorf("failed to do something: %w", err)
    }
    return nil
}

func fetchResource() error {
    return ErrNotFound
}

Это позволяет вам проверять наличие конкретных ошибок, а также поддерживать стек ошибок, который дает больше информации о том, что пошло не так.

Пример 4. Расширение ошибок с помощью метода Unwrap()

Go также предоставляет способ извлечь обернутую ошибку с помощью метода Unwrap(). Внедрив этот метод в свои пользовательские типы ошибок, вы можете разрешить дальнейшее развертывание ошибок.

package main

import (
    "errors"
    "fmt"
)

type MyError struct {
    Code    int
    Message string
    Err     error
}

func (e *MyError) Error() string {
    return fmt.Sprintf("Code %d: %s", e.Code, e.Message)
}

func (e *MyError) Unwrap() error {
    return e.Err
}

func main() {
    err := doSomething()
    if err != nil {
        fmt.Println("Error:", err)
        if errors.Is(err, ErrNotFound) {
            fmt.Println("The resource was not found.")
        }
    }
}

var ErrNotFound = errors.New("resource not found")

func doSomething() error {
    err := fetchResource()
    if err != nil {
        return &MyError{
            Code:    500,
            Message: "Something went wrong",
            Err:     err,
        }
    }
    return nil
}

func fetchResource() error {
    return ErrNotFound
}

Здесь MyError имеет метод Unwrap(), который возвращает упакованную ошибку. Это позволяет глубже изучить и обработать основную ошибку.

Пример 5: Проверка ошибок с помощью функции error.As

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

package main

import (
    "errors"
    "fmt"
)

type MyError struct {
    Code    int
    Message string
    Err     error
}

func (e *MyError) Error() string {
    return fmt.Sprintf("Code %d: %s: %v", e.Code, e.Message, e.Err)
}

func main() {
    err := doSomething()
    var mErr *MyError
    // another way to initialize custom error
    // mErr := &MyError{}
    if errors.As(err, &mErr) {
        fmt.Println("Error:", mErr)
    }
}

// doSomething attempts to fetch a resource and returns an error if it fails.
// If the error is ErrNotFound, it is wrapped in a MyError with a code of 500.
func doSomething() error {
    err := fetchResource()
    if err != nil {
        return &MyError{
            Code:    500,
            Message: "Something went wrong",
            Err:     err,
        }
    }
    return nil
}

var ErrNotFound = errors.New("resource not found")

func fetchResource() error {
    return ErrNotFound
}

Лучшие практики для устранения пользовательских ошибок в Go

  1. Используйте пользовательские ошибки экономно: Пользовательские ошибки очень эффективны, но могут усложнить работу. Используйте их, когда они дают существенные преимущества, например лучшую категоризацию ошибок или дополнительный контекст.

  2. Используйте упаковку и развертывание: Обертывание ошибок с помощью дополнительного контекста и их последующее развертывание — лучший способ улучшить отладку ошибок.

  3. Задокументируйте типы ошибок: Убедитесь, что все пользовательские ошибки хорошо задокументированы, чтобы было понятно их назначение и использование.

  4. Предпочитайте значения ошибок для сравнения: Если вам нужно сравнить ошибки, рассмотрите возможность использования заранее определенных значений ошибок (контрольных ошибок) для единообразия и ясности.

Заключение

Пользовательские ошибки в Go предоставляют гибкий и мощный способ управления ошибками в ваших приложениях. Создавая собственные типы ошибок, оборачивая ошибки для дополнительного контекста и разворачивая их для более глубокой проверки, вы можете создать надежные и удобные в обслуживании механизмы обработки ошибок. Это не только помогает при отладке, но и улучшает общее качество вашего кода Go.
Выбирайте свою стратегию с ошибками и используйте последовательные ошибки во всем проекте.

Заявление о выпуске Эта статья воспроизведена по адресу: https://dev.to/ankitmalikg/create-custom-errors-in-golang-3mdl?1. В случае нарушения авторских прав свяжитесь с [email protected], чтобы удалить ее.
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3