В стандартном пакете net
используется классический подход с типами ошибок, реализующими определенные интерфейсы:
// Пример из пакета net
type Error interface {
error
Timeout() bool // Recoverable - можно повторить операцию
Temporary() bool // Recoverable - временная ошибка
}
// Пример использования
if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
// Повторяем операцию после задержки
}
Особенности подхода net:
Timeout()
- ошибка по таймаутуTemporary()
- временная ошибкаfalse
- считается fatal ошибкойvar (
ErrFatal = errors.New("fatal error")
ErrRecoverable = errors.New("recoverable error")
)
func Process() error {
if condition {
return fmt.Errorf("%w: description", ErrRecoverable)
}
return ErrFatal
}
// Проверка
err := Process()
if errors.Is(err, ErrRecoverable) {
// Повторяем операцию
}
type ErrorKind int
const (
KindRecoverable ErrorKind = iota
KindFatal
)
type MyError struct {
Kind ErrorKind
Message string
}
func (e *MyError) Error() string {
return e.Message
}
func (e *MyError) IsRecoverable() bool {
return e.Kind == KindRecoverable
}
type RecoverableError interface {
error
Recoverable() bool
}
type myError struct {
recoverable bool
msg string
}
func (e *myError) Error() string { return e.msg }
func (e *myError) Recoverable() bool { return e.recoverable }
func Process() error {
return &myError{recoverable: true, msg: "retry later"}
}
// Проверка
err := Process()
var re RecoverableError
if errors.As(err, &re) && re.Recoverable() {
// Обработка recoverable
}
errors.Is
/errors.As
вместо прямого type assertionfmt.Errorf
и %w
Пример комплексного решения:
func HandleError(err error) {
switch {
case errors.Is(err, ErrNetworkTimeout):
log.Printf("Recoverable network error: %v", err)
time.Sleep(retryDelay)
RetryOperation()
case errors.Is(err, ErrInvalidInput):
log.Printf("Fatal error: %v", err)
os.Exit(1)
default:
log.Printf("Unknown error: %v", err)
}
}
современный Go предлагает гибкие механизмы для классификации ошибок через комбинацию sentinel errors, кастомных типов и интерфейсов, с проверкой через errors.Is/As
. Это более выразительно и поддерживаемо, чем классический подход net пакета.