Урок объясняет, как устроена обработка ошибок в Go: возврат ошибок как последнего значения, создание простых ошибок через errors.New, реализация кастомных ошибок, использование errors.Is и errors.As, а также принципы корректного проектирования ошибок.
Обработка ошибок - фундаментальная часть Go. В языке нет исключений, вместо этого ошибки возвращаются как последнее возвращаемое значение функций. Это делает логику ошибок явной, понятной и предсказуемой.
nil.type error interface {
Error() string
}
Это делает ошибки обычными значениями, с которыми можно работать.
Стандартный пакет errors позволяет быстро создавать простые ошибки:
import "errors"
func divide(lhs, rhs int) (int, error) {
if rhs == 0 {
return 0, errors.New("cannot divide by zero")
}
return lhs / rhs, nil
}
Такой подход удобен, когда ошибка не требует сложных данных.
Можно создавать собственные типы ошибок:
type DivError struct {
a, b int
}
func (d *DivError) Error() string {
return fmt.Sprintf("Cannot divide by zero: %d / %d", d.a, d.b)
}
Почему метод должен быть с указателем?
func div(a, b int) (int, error) {
if b == 0 {
return 0, &DivError{a, b}
}
return a / b, nil
}
answer, err := div(9, 0)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(answer)
Когда нужно проверить, относится ли ошибка к определённому типу:
var inputErr = &UserError{"Input Error"}
if errors.Is(err, inputErr) {
fmt.Println("Input error:", err)
} else {
fmt.Println("Other error:", err)
}
errors.Is проверяет всю цепочку ошибок, включая обёртки.
Когда нужно получить объект ошибки конкретного типа:
var target *UserError
if errors.As(err, &target) {
fmt.Println("User error:", target)
} else {
fmt.Println("Other error:", err)
}
Если ошибка соответствует типу, она будет извлечена в переменную
target.
errors.New.error.if err != nil.errors.Is - для проверки типа ошибки.errors.As - для извлечения ошибки нужного типа.