Пакет errors
Обзор
Пакет errors реализует функции для работы с ошибками.
Функция New создаёт ошибки, содержимое которых ограничивается текстовым сообщением.
Ошибка e оборачивает другую ошибку, если тип e содержит один из методов
Unwrap() error Unwrap() []error
Если e.Unwrap() возвращает ненулевую ошибку w или срез, содержащий w, то говорят, что e оборачивает w. Возврат nil из e.Unwrap() означает, что e не оборачивает ни одной ошибки. Метод Unwrap не должен возвращать []error, содержащий значение nil.
Простой способ создавать обёрнутые ошибки — вызвать fmt.Errorf и применить глагол %w к аргументу-ошибке:
wrapsErr := fmt.Errorf("... %w ...", ..., err, ...)
Последовательное раскрытие обёрток ошибки образует дерево. Функции Is и As исследуют дерево ошибки: сначала проверяют саму ошибку, а затем по очереди дерево каждого её дочернего элемента (обход в глубину, сначала корень).
Подробнее о принципах оборачивания ошибок и о том, когда следует создавать обёртки, см. https://go.dev/blog/go1.13-errors.
Функция Is исследует дерево первого аргумента в поисках ошибки, соответствующей второму аргументу. Она сообщает, найдено ли совпадение. Её следует использовать вместо простых проверок на равенство:
if errors.Is(err, fs.ErrExist)
предпочтительнее, чем
if err == fs.ErrExist
поскольку первый вариант сработает, если err оборачивает io/fs.ErrExist.
Функция AsType исследует дерево аргумента в поисках ошибки, тип которой соответствует аргументу типа. При успехе она возвращает соответствующее значение этого типа и true. В противном случае она возвращает нулевое значение этого типа и false. Форма
if perr, ok := errors.AsType[*fs.PathError](err); ok {
fmt.Println(perr.Path)
}
предпочтительнее, чем
if perr, ok := err.(*fs.PathError); ok {
fmt.Println(perr.Path)
}
поскольку первый вариант сработает, если err оборачивает *io/fs.PathError.
Пример
Код:
if err := oops(); err != nil {
fmt.Println(err)
}
Вывод:
1989-03-15 22:30:00 +0000 UTC: the file system has gone away
Указатель
Примеры
Файлы пакета
errors.go join.go wrap.go
Переменные
ErrUnsupported указывает на то, что запрошенную операцию нельзя выполнить, поскольку она не поддерживается. Например, вызов os.Link в файловой системе, не поддерживающей жёсткие ссылки.
Функции и методы не должны возвращать эту ошибку; вместо этого им следует возвращать ошибку с соответствующим контекстом, которая удовлетворяет
errors.Is(err, errors.ErrUnsupported)
либо путём непосредственного оборачивания ErrUnsupported, либо путём реализации метода Is.
Функции и методы должны описывать случаи, в которых будет возвращена ошибка, оборачивающая эту.
var ErrUnsupported = New("unsupported operation") func As 1.13
func As(err error, target any) bool
As находит первую ошибку в дереве err, соответствующую target, и, если такая найдена, присваивает target значение этой ошибки и возвращает true. В противном случае возвращает false.
В большинстве случаев предпочтительнее использовать AsType. As эквивалентна AsType, но устанавливает аргумент target вместо возврата соответствующей ошибки и не требует, чтобы аргумент target реализовывал error.
Дерево состоит из самой err и ошибок, полученных последовательными вызовами её метода Unwrap() error или Unwrap() []error. Если err оборачивает несколько ошибок, As исследует err, а затем её дочерние элементы с помощью обхода в глубину.
Ошибка соответствует target, если её конкретное значение можно присвоить значению, на которое указывает target, или если у ошибки есть метод As(any) bool, для которого As(target) возвращает true. Во втором случае метод As отвечает за установку target.
Тип ошибки может предоставлять метод As, чтобы с ним можно было работать как с другим типом ошибки.
As вызывает панику, если target не является ненулевым указателем на тип, реализующий error, или на тип интерфейса.
Пример
Код:
if _, err := os.Open("non-existing"); err != nil {
var pathError *fs.PathError
if errors.As(err, &pathError) {
fmt.Println("Failed at path:", pathError.Path)
} else {
fmt.Println(err)
}
}
Вывод:
Failed at path: non-existing
func AsType 1.26
func AsType[E error](err error) (E, bool)
AsType находит первую ошибку в дереве err, соответствующую типу E, и, если такая найдена, возвращает значение этой ошибки и true. В противном случае возвращает нулевое значение E и false.
Дерево состоит из самой err и ошибок, полученных последовательными вызовами её метода Unwrap() error или Unwrap() []error. Если err оборачивает несколько ошибок, AsType исследует err, а затем её дочерние элементы с помощью обхода в глубину.
Ошибка err соответствует типу E, если выполняется утверждение типа err.(E) или если у ошибки есть метод As(any) bool, для которого err.As(target) возвращает true, когда target является ненулевым *E. Во втором случае метод As отвечает за установку target.
Пример
Код:
if _, err := os.Open("non-existing"); err != nil {
if pathError, ok := errors.AsType[*fs.PathError](err); ok {
fmt.Println("Failed at path:", pathError.Path)
} else {
fmt.Println(err)
}
}
Вывод:
Failed at path: non-existing
func Is 1.13
func Is(err, target error) bool
Is сообщает, соответствует ли target какая-либо ошибка в дереве err. Target должен быть сравнимым.
Дерево состоит из самой err и ошибок, полученных последовательными вызовами её метода Unwrap() error или Unwrap() []error. Если err оборачивает несколько ошибок, Is исследует err, а затем её дочерние элементы с помощью обхода в глубину.
Ошибка считается соответствующей target, если она равна target или реализует метод Is(error) bool, для которого Is(target) возвращает true.
Тип ошибки может предоставлять метод Is, чтобы его можно было считать эквивалентным существующей ошибке. Например, если MyError определяет
func (m MyError) Is(target error) bool { return target == fs.ErrExist }
то Is(MyError{}, fs.ErrExist) возвращает true. Пример в стандартной библиотеке см. в syscall.Errno.Is. Метод Is должен только поверхностно сравнивать err и target и не должен вызывать Unwrap ни для одного из них.
Пример
Код:
if _, err := os.Open("non-existing"); err != nil {
if errors.Is(err, fs.ErrNotExist) {
fmt.Println("file does not exist")
} else {
fmt.Println(err)
}
}
Вывод:
file does not exist
func Join 1.20
func Join(errs ...error) error
Join возвращает ошибку, оборачивающую переданные ошибки. Значения ошибок nil отбрасываются. Join возвращает nil, если все значения в errs равны nil. Строковое представление ошибки — это объединение строк, полученных вызовом метода Error для каждого элемента errs, с символом новой строки между строками.
Ненулевая ошибка, возвращённая Join, реализует метод Unwrap() []error. Ошибки можно исследовать с помощью Is и As.
Пример
Код:
err1 := errors.New("err1")
err2 := errors.New("err2")
err := errors.Join(err1, err2)
fmt.Println(err)
if errors.Is(err, err1) {
fmt.Println("err is err1")
}
if errors.Is(err, err2) {
fmt.Println("err is err2")
}
fmt.Println(err.(interface{ Unwrap() []error }).Unwrap())
Вывод:
err1 err2 err is err1 err is err2 [err1 err2]
func New
func New(text string) error
New возвращает ошибку, строковое представление которой соответствует заданному тексту. Каждый вызов New возвращает отдельное значение ошибки, даже если текст совпадает.
Пример
Код:
err := errors.New("emit macho dwarf: elf header corrupted")
if err != nil {
fmt.Print(err)
}
Вывод:
emit macho dwarf: elf header corrupted
Пример (Errorf)
Функция Errorf пакета fmt позволяет использовать средства форматирования пакета для создания информативных сообщений об ошибках.
Код:
const name, id = "bimmler", 17
err := fmt.Errorf("user %q (id %d) not found", name, id)
if err != nil {
fmt.Print(err)
}
Вывод:
user "bimmler" (id 17) not found
Пример (Unique)
Каждый вызов [errors.New] возвращает уникальный экземпляр ошибки, даже если аргументы совпадают. Чтобы сопоставлять ошибки, созданные с помощью [errors.New], объявите ошибку-маркер и используйте её повторно.
Код:
err1 := OopsNew()
err2 := OopsNew()
fmt.Println("Errors using distinct errors.New calls:")
fmt.Printf("Is(%q, %q) = %v\n", err1, err2, errors.Is(err1, err2))
err3 := OopsSentinel()
err4 := OopsSentinel()
fmt.Println()
fmt.Println("Errors using a sentinel error:")
fmt.Printf("Is(%q, %q) = %v\n", err3, err4, errors.Is(err3, err4))
Вывод:
Errors using distinct errors.New calls:
Is("an error", "an error") = false
Errors using a sentinel error:
Is("an error", "an error") = true
func Unwrap 1.13
func Unwrap(err error) error
Unwrap возвращает результат вызова метода Unwrap для err, если тип err содержит метод Unwrap, возвращающий error. В противном случае Unwrap возвращает nil.
Unwrap вызывает только метод вида "Unwrap() error". В частности, Unwrap не раскрывает обёртки ошибок, возвращённых функцией Join.
Пример
Код:
err1 := errors.New("error1")
err2 := fmt.Errorf("error2: [%w]", err1)
fmt.Println(err2)
fmt.Println(errors.Unwrap(err2))
Вывод:
error2: [error1] error1
© Google, Inc.
Licensed under the Creative Commons Attribution License 3.0.
http://golang.org/pkg/errors/