пятница, 1 февраля 2019 г.

Эффективный Go: ошибки

Библиотечные процедуры часто должны возвращать какую-то индикацию ошибки вызывающему. Множественные вовзращаемые значения в Go делают простым возврат подробного описания ошибки вместе с нормальным возвращаемым значением. Рекомендуется использовать эту возможность для предоставления подробной информации об ошибках. Например, как мы увидим, os.Open не просто возвращает указатель nil при ошибке, он также возвращает значение ошибки, которая описывает, что пошло не так.

Как правило, ошибки имеют тип error, простой встроенный интерфейс.

type error interface {
    Error() string
}

Автор библиотеки может свободно реализовать этот интерфейс с более богатой моделью под капотом, что делает возможным не только увидеть саму ошибку, но и предоставить некоторый контекст. Как уже упоминалось, наряду с обычным *os.File возвращаемым значением, os.Open также возвращает значение ошибки. Если файл успешно открыт, ошибка будет nil, но когда есть проблема, он будет содержать os.PathError:

// PathError записывает ошибку и операцию и
// путь к файлу, который ее вызвал.
type PathError struct {
    Op string    // "open", "unlink", и т.д.
    Path string  // Связанный файл.
    Err error    // Возвращается системным вызовом.
}

func (e *PathError) Error() string {
    return e.Op + " " + e.Path + ": " + e.Err.Error()
}

Error в PathError генерирует похожую строку:

open /etc/passwx: no such file or directory

Такая ошибка, которая включает проблемное имя файла, операцию, и ошибку операционной системы, которую это вызвало, полезна даже если напечатана далеко от вызова, который вызвал ее; это гораздо более информативно, чем просто "no such file or directory".

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

Вызывающие, которые заботятся о точных деталях ошибки, могут использовать переключатель типа или утверждение типа для поиска конкретных ошибок и извлекать детали. Для PathErrors это может включать проверку внутреннего Err поля для восстановливаемых неисправностей.

for try := 0; try < 2; try++ {
    file, err = os.Create(filename)
    if err == nil {
        return
    }
    if e, ok := err.(*os.PathError); ok && e.Err == syscall.ENOSPC {
        deleteTempFiles()  // Восстановить некоторое пространство.
        continue
    }
    return
}

Второй оператор if здесь - это утверждение типа. Если произойдет сбой, ok будет ложным, а e будет nil. Если все пройдет успешно, ok будет true, означающее что ошибка была типа *os.PathError, а затем e, который мы можем изучить для получения дополнительной информации об ошибке.


Читайте также:


Комментариев нет:

Отправить комментарий