[Перевод] Часть 31: Пользовательские ошибки в golang

Go
  • Оригинальный адрес:Part 31: Custom Errors
  • Оригинальный автор:Naveen R
  • Переводчик: хаки хаки Пожалуйста, укажите источник.

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

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

использоватьNewфункция создания пользовательскихerror

Создать пользовательскийerrorСамый простой способ - использоватьerrorsупаковкаNewфункция.

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

// Package errors implements functions to manipulate errors.
  package errors

  // New returns an error that formats as the given text.
  func New(text string) error {
      return &errorString{text}
  }

  // errorString is a trivial implementation of error.
  type errorString struct {
      s string
  }

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

Реализация очень проста.errorStringэто строка с однимsтип конструкции.errorинтерфейсErrorМетод заключается в использовании в строке 14errorStringРеализован приемник указателя.

строка 5NewФункция принимает строковый параметр, используя этот параметр для созданияerrorStringзначение типа и вернуть его адрес, новыйerrorЭто завершено.

Теперь мы знаемNewКак работает функция, давайте использовать ее в наших собственных программах для создания пользовательскихerror.

Мы создадим простую программу, которая вычисляет площадь круга и возвращает значение, если радиус отрицателен.error.

package main

import (
    "errors"
    "fmt"
    "math"
)

func circleArea(radius float64) (float64, error) {
    if radius < 0 {
        return 0, errors.New("Area calculation failed, radius is less than zero")
    }
    return math.Pi * radius * radius, nil
}

func main() {
    radius := -20.0
    area, err := circleArea(radius)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("Area of circle %0.2f", area)
}

Run in playground

В приведенной выше программе мы проверяем, меньше ли радиус нуля в строке 10. Если это так, верните 0 и соответствующийerrorсодержание. В строке 13, если радиус больше 0, вычислите площадь и верните значение какnilизerror.

В основной функции проверяем строку 19errorЭтоnil. если неnil, вывести ошибку и вернуться, иначе вывести площадь области.

В этой программе радиус меньше нуля, поэтому она напечатает,

Area calculation failed, radius is less than zero

использоватьErrorfзаerrorдобавить больше информации

Приведенная выше программа работает нормально, но если мы хотим напечатать точное сообщение об ошибке, это немного сложно. эта сценаfmtупаковкаErrorfФункции пригодятся. Эта функция принимает параметр строкового формата и возвращает строку в видеerrorзначение .

давай попробуемErrorfфункция,

package main

import (
    "fmt"
    "math"
)

func circleArea(radius float64) (float64, error) {
    if radius < 0 {
        return 0, fmt.Errorf("Area calculation failed, radius %0.2f is less than zero", radius)
    }
    return math.Pi * radius * radius, nil
}

func main() {
    radius := -20.0
    area, err := circleArea(radius)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("Area of circle %0.2f", area)
}

Run in playground

В приведенной выше программе строка 10 используетErrorf, печатает фактическое значение радиуса, вызвавшее ошибку, запуск этой программы выводит,

Area calculation failed, radius -20.00 is less than zero

Используйте типы структур и поля для предоставления информации оerrorБольше информации о

Также можно использовать тип структуры, который реализует интерфейс ошибки какerror. Это дает нам больше гибкости. В нашем примере, если мы хотим увидеть ошибки, единственный способ — разобратьArea calculation failed, radius -20.00 is less than zero. Это неподходящий подход, потому что, если описание изменится, логика нашего кода должна быть изменена.

Мы будем использовать поля структуры для предоставленияerrиradius. Мы создадим реализациюerrorСтруктурный тип интерфейса и использует его поля для предоставления дополнительной информации о нем.

Первым шагом является создание типа структуры для представленияerror. Соглашение об именах типовErrorконец. Поэтому мы называем тип структуры какareaError

type areaError struct {
    err    string
    radius float64
}

Вышеуказанный тип структуры имеет полеradius, в котором хранитсяerrorзначение радиуса , иerrПоле хранит фактическое содержание ошибки.

Следующим шагом является реализацияerrorинтерфейс.

func (e *areaError) Error() string {
    return fmt.Sprintf("radius %0.2f: %s", e.radius, e.err)
}

В приведенном выше фрагменте кода мы используем приемник указателя.* areaErrorреализует неправильный интерфейсErrorметод. Этот метод печатаетradiusиerrописывать.

Давай напишемmainфункция иcircleAreaфункция завершения программы.

package main

import (
    "fmt"
    "math"
)

type areaError struct {
    err    string
    radius float64
}

func (e *areaError) Error() string {
    return fmt.Sprintf("radius %0.2f: %s", e.radius, e.err)
}

func circleArea(radius float64) (float64, error) {
    if radius < 0 {
        return 0, &areaError{"radius is negative", radius}
    }
    return math.Pi * radius * radius, nil
}

func main() {
    radius := -20.0
    area, err := circleArea(radius)
    if err != nil {
        if err, ok := err.(*areaError); ok {
            fmt.Printf("Radius %0.2f is less than zero", err.radius)
            return
        }
        fmt.Println(err)
        return
    }
    fmt.Printf("Area of rectangle1 %0.2f", area)
}

Run in playgroud

В приведенной выше программе строка 17 изcircleAreaИспользуется для вычисления площади круга. Эта функция сначала проверяет, меньше ли радиус нуля, и, если да, использует радиус ошибки и соответствующее описание ошибки для созданияareaError, затем вернуться на строку 19areaErrorадрес и содержание ошибки. Поэтому мы предоставляем большеerrorинформацию, в данном примере с использованиемerrorПоля структуры реализуют настройку.

Если радиус неотрицательный, эта функция вычисляет и возвращает сумму площадейnil

в строке 26mainВ функции пытаемся вычислить площадь круга с радиусом -20. Будет возвращена ошибка, поскольку радиус меньше нуля.

Проверяем на строке 27errЭтоnil, и утвердите в следующей строкеerrда* areaErrorтип. если* areaError类型, используем в строке 29err.radiusвызватьerrorизradius, затем распечатайте пользовательское содержимое ошибки и вернитесь из программы.

вывод,

Radius -20.00 is less than zero

Теперь воспользуемся второй стратегией, описанной в предыдущем руководстве, и воспользуемся подходом с пользовательским типом ошибки для предоставления информации оerrorЧтобы получить больше информации.

Метод использования структурного типа обеспечиваетerrorБольше информации о

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

Первым шагом является создание представленияerrorСтруктура.

type areaError struct {
    err    string //error description
    length float64 //length which caused the error
    width  float64 //width which caused the error
}

Приведенный выше тип структуры ошибки содержит поле описания ошибки.errи длинаlengthи ширинаwidth.

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

func (e *areaError) Error() string {
    return e.err
}

func (e *areaError) lengthNegative() bool {
    return e.length < 0
}

func (e *areaError) widthNegative() bool {
    return e.width < 0
}

В приведенном выше фрагменте кода мы начинаем сErrorМетод возвращает описание ошибкиe.err. когдаlengthКогда меньше 0,lengthNegativeметод возвращаетtrue, и когдаwidthКогда меньше 0,widthNegativeметод возвращаетtrue. В данном случае эти два метода предоставляют информацию о том, произошел ли сбой вычисления площади из-за отрицательной длины или отрицательной ширины. Поэтому мы используемerrorметоды типа структуры для предоставления дополнительной информации о файлах .

Следующим шагом является реализация функции вычисления площади.

func rectArea(length, width float64) (float64, error) {
    err := ""
    if length < 0 {
        err += "length is less than zero"
    }
    if width < 0 {
        if err == "" {
            err = "width is less than zero"
        } else {
            err += ", width is less than zero"
        }
    }
    if err != "" {
        return 0, &areaError{err, length, width}
    }
    return length * width, nil
}

вышеrectAreaФункция проверяет, если длина или ширина меньше 0, а если да, возврат 0 иerror, иначе возвращает площадь прямоугольника иnil. Давайте создадимmainфункция для завершения всей программы.

func main() {
    length, width := -5.0, -9.0
    area, err := rectArea(length, width)
    if err != nil {
        if err, ok := err.(*areaError); ok {
            if err.lengthNegative() {
                fmt.Printf("error: length %0.2f is less than zero\n", err.length)

            }
            if err.widthNegative() {
                fmt.Printf("error: width %0.2f is less than zero\n", err.width)

            }
            return
        }
        fmt.Println(err)
        return
    }
    fmt.Println("area of rect", area)
}

существуетmainработает, проверяемerrЭтоnil. если это неnil, мы утверждаем в следующей строке* areaError. затем используйтеlengthNegativeиwidthNegativeметод, который проверяет, вызвана ли ошибка отрицательной длиной или отрицательной шириной. Мы печатаем соответствующиеerrorсодержание и возврат из программы. Поэтому мы используем метод типа структуры, чтобы предоставить больше информации о ней.

Если ошибок нет, область прямоугольника будет напечатана.

Наконец, полная программа размещена для справки.

package main

import "fmt"

type areaError struct {
    err    string  //error description
    length float64 //length which caused the error
    width  float64 //width which caused the error
}

func (e *areaError) Error() string {
    return e.err
}

func (e *areaError) lengthNegative() bool {
    return e.length < 0
}

func (e *areaError) widthNegative() bool {
    return e.width < 0
}

func rectArea(length, width float64) (float64, error) {
    err := ""
    if length < 0 {
        err += "length is less than zero"
    }
    if width < 0 {
        if err == "" {
            err = "width is less than zero"
        } else {
            err += ", width is less than zero"
        }
    }
    if err != "" {
        return 0, &areaError{err, length, width}
    }
    return length * width, nil
}

func main() {
    length, width := -5.0, -9.0
    area, err := rectArea(length, width)
    if err != nil {
        if err, ok := err.(*areaError); ok {
            if err.lengthNegative() {
                fmt.Printf("error: length %0.2f is less than zero\n", err.length)

            }
            if err.widthNegative() {
                fmt.Printf("error: width %0.2f is less than zero\n", err.width)

            }
            return
        }
    }
    fmt.Println("area of rect", area)
}

Run in playgroundвывод программы,

error: length -5.00 is less than zero
error: width -9.00 is less than zero

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

Третий способ проще – использовать метод прямого сравнения. Я оставлю это в качестве упражнения для вас, чтобы выяснить, как использовать эту стратегию для настройки нашихerrorЧтобы получить больше информации.