Используя только стандартную библиотеку, как обернуть ошибку в пользовательскую ошибку? - PullRequest
1 голос
/ 24 апреля 2020

Поскольку Go 1.13, у нас есть возможность объединять ошибки, разворачивать их и проверять, совпадает ли любая ошибка в цепочке с какими-либо из ожидаемых ошибок, с помощью errors.Is() и errors.As().

Чтобы обернуть ошибку все, что вам нужно сделать, это использовать %w глагол с fmt.Errorf(), как показано ниже.

fmt.Errorf("Custom message: %w", err)

Это очень просто, он включает err в другое с дополнительным сообщением. Но скажем, мне нужно больше контекста, чем просто сообщение. Как мне обернуть err в мою собственную структурированную ошибку? Использование только стандартной библиотеки Go 1.13+.

Ответы [ 2 ]

2 голосов
/ 24 апреля 2020

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

type MyError struct {
    Inner error
    // Provide any additional fields that you need.
    Message string
    AdditionalContext string 
}

// Error is mark the struct as an error.
func (e *MyError) Error() string {
    return fmt.Sprintf("error caused due to %v; message: %v; additional context: %v", e.Inner, e.Message, e.AdditionalContext)
}

// Unwrap is used to make it work with errors.Is, errors.As.
func (e *MyError) Unwrap() error {
    // Return the inner error.
    return e.Inner
}

// WrapWithMyError to easily create a new error which wraps the given error.
func WrapWithMyError(err error, message string, additionalContext string) error {
    return &MyError {
        Inner: err,
        Message: message,
        AdditionalContext: additionalContext,
    }
}

Вам необходимо реализовать интерфейсы Error и Unwrap, чтобы использовать новые функции errors.Is и errors.As.

0 голосов
/ 24 апреля 2020

Ошибки - это интерфейс (удовлетворяется error() string). Таким образом, вы можете сделать другой тип ошибки следующим образом:

type myCustomError struct {
  Message    string
  StatusCode int
}

func (m myCustomError) error() string {
  return fmt.Sprintf("Code %d: \tMessage: %s", m.StatusCode, m.Message) 
}

Теперь вы можете использовать ошибку, которая выдается как пользовательская ошибка с

_, err := doStuff()
var v myCustomError
if errors.As(err, &v) {
   // now v is parsed 
}
...