Создание своих ошибок
Создание своих ошибок в Go реализуется через определение пользовательского типа, который удовлетворяет встроенному интерфейсу error. Интерфейс error требует реализации метода Error, который возвращает строку с описанием ошибки. Пользовательский тип может хранить любые дополнительные поля, такие как код ошибки, временная метка или другие данные, что делает обработку ошибок более гибкой и информативной.
Создание кастомной ошибки через структуру
Самый распространённый способ создания своей ошибки — определение структуры, реализующей метод Error. В этом методе можно сформировать строковое представление ошибки, используя поля структуры. Такой подход позволяет передавать в ошибке множество параметров.
package main
import (
"fmt"
)
type MyError struct {
Code int
Message string
}
func (e MyError) Error() string {
return fmt.Sprintf("error %d: %s", e.Code, e.Message)
}
func doSomething() error {
return MyError{Code: 404, Message: "not found"}
}
func main() {
err := doSomething()
if err != nil {
fmt.Println(err)
}
}
Результат выполнения кода:
"error 404: not found"
Использование указателя на структуру
Часто метод Error реализуют с использованием указателя на структуру (*MyError). Это позволяет избежать копирования структуры при вызове метода и обеспечивает согласованность, если структура содержит изменяемые поля или большие объёмы данных.
package main
import (
"fmt"
)
type CustomError struct {
Code int
Message string
}
func (e *CustomError) Error() string {
return fmt.Sprintf("custom error #%d: %s", e.Code, e.Message)
}
func process() error {
return &CustomError{Code: 500, Message: "internal server error"}
}
func main() {
err := process()
if err != nil {
fmt.Println(err)
}
}
Результат выполнения кода:
"custom error #500: internal server error"
Использование функции-конструктора
Для удобства создания кастомных ошибок часто используют функцию-конструктор, которая принимает необходимые параметры и возвращает ошибку. Это делает код более читаемым и позволяет инкапсулировать логику создания ошибки, например, для автоматического заполнения временной метки.
package main
import (
"fmt"
"time"
)
type AppError struct {
Time time.Time
Code int
Message string
}
func (e AppError) Error() string {
return fmt.Sprintf("[%s] %d: %s", e.Time.Format("2006-01-02 15:04:05"), e.Code, e.Message)
}
func NewAppError(code int, msg string) error {
return AppError{
Time: time.Now(),
Code: code,
Message: msg,
}
}
func main() {
err := NewAppError(403, "forbidden")
if err != nil {
fmt.Println(err)
}
}
Результат выполнения кода (время будет отличаться):
"[2026-09-04 12:00:00] 403: forbidden"
Сравнение кастомных ошибок
При необходимости сравнения кастомных ошибок рекомендуется использовать приведение типов (type assertion) или метод errors.As. Это позволяет получить доступ к полям структуры и выполнить нужные проверки, например, сравнить код ошибки.
package main
import (
"fmt"
"errors"
)
type MyError struct {
Code int
}
func (e MyError) Error() string {
return fmt.Sprintf("code %d", e.Code)
}
func check(err error) bool {
var myErr MyError
if errors.As(err, &myErr) {
return myErr.Code == 404
}
return false
}
func main() {
err := MyError{Code: 404}
fmt.Println(check(err))
}
Результат выполнения кода:
"true"
Смотрите также
-
функцию
errors.New,
которая создаёт простую ошибку -
функцию
fmt.Errorf,
которая форматирует сообщение об ошибке -
функцию
errors.Is,
которая проверяет, является ли ошибка конкретной -
функцию
errors.As,
которая выполняет приведение типа ошибки