自定义错误 #
一、实现error接口 #
1.1 基本实现 #
go
type MyError struct {
Message string
}
func (e *MyError) Error() string {
return e.Message
}
1.2 使用自定义错误 #
go
func doSomething() error {
return &MyError{Message: "something went wrong"}
}
二、自定义错误类型 #
2.1 带更多信息的错误 #
go
type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation error on field %s: %s", e.Field, e.Message)
}
func validateUser(name string) error {
if name == "" {
return &ValidationError{
Field: "name",
Message: "cannot be empty",
}
}
return nil
}
2.2 带错误码的错误 #
go
type ErrorCode int
const (
ErrNotFound ErrorCode = iota + 1
ErrInvalidInput
ErrUnauthorized
)
type AppError struct {
Code ErrorCode
Message string
}
func (e *AppError) Error() string {
return fmt.Sprintf("[%d] %s", e.Code, e.Message)
}
2.3 带堆栈信息的错误 #
go
type StackError struct {
Message string
Stack []byte
}
func (e *StackError) Error() string {
return fmt.Sprintf("%s\n%s", e.Message, e.Stack)
}
func NewStackError(msg string) error {
return &StackError{
Message: msg,
Stack: debug.Stack(),
}
}
三、错误类型断言 #
3.1 类型断言 #
go
err := validateUser("")
if ve, ok := err.(*ValidationError); ok {
fmt.Printf("Field: %s, Message: %s\n", ve.Field, ve.Message)
}
3.2 类型switch #
go
switch e := err.(type) {
case *ValidationError:
fmt.Printf("Validation: %s\n", e.Field)
case *AppError:
fmt.Printf("App Error: %d\n", e.Code)
default:
fmt.Println("Unknown error")
}
3.3 errors.As #
go
var ve *ValidationError
if errors.As(err, &ve) {
fmt.Printf("Field: %s\n", ve.Field)
}
四、实际应用 #
4.1 HTTP错误 #
go
type HTTPError struct {
StatusCode int
Message string
}
func (e *HTTPError) Error() string {
return fmt.Sprintf("HTTP %d: %s", e.StatusCode, e.Message)
}
func NewHTTPError(status int, msg string) *HTTPError {
return &HTTPError{
StatusCode: status,
Message: msg,
}
}
func handleRequest(w http.ResponseWriter, r *http.Request) error {
if !isAuthenticated(r) {
return NewHTTPError(http.StatusUnauthorized, "unauthorized")
}
return nil
}
4.2 数据库错误 #
go
type DBError struct {
Query string
Message string
Cause error
}
func (e *DBError) Error() string {
return fmt.Sprintf("DB error: %s (query: %s)", e.Message, e.Query)
}
func (e *DBError) Unwrap() error {
return e.Cause
}
4.3 业务错误 #
go
type BusinessError struct {
Code string
Message string
}
func (e *BusinessError) Error() string {
return fmt.Sprintf("[%s] %s", e.Code, e.Message)
}
var (
ErrUserNotFound = &BusinessError{Code: "USER_001", Message: "User not found"}
ErrInvalidInput = &BusinessError{Code: "INPUT_001", Message: "Invalid input"}
)
五、最佳实践 #
5.1 提供有用信息 #
go
type Error struct {
Op string
Err error
}
func (e *Error) Error() string {
return fmt.Sprintf("%s: %v", e.Op, e.Err)
}
5.2 实现Unwrap #
go
func (e *MyError) Unwrap() error {
return e.Cause
}
5.3 使用errors.As检查 #
go
var appErr *AppError
if errors.As(err, &appErr) {
// 处理特定错误
}
六、总结 #
自定义错误要点:
| 方法 | 说明 |
|---|---|
| 实现Error() | 满足error接口 |
| 类型断言 | 检查错误类型 |
| errors.As | 安全的类型检查 |
| Unwrap | 支持错误解包 |
关键点:
- 实现接口:实现Error() string方法
- 丰富信息:添加字段提供更多上下文
- 类型检查:使用errors.As安全检查
- 错误码:定义错误码便于处理
- Unwrap:支持错误链
准备好学习错误包装了吗?让我们进入下一章!
最后更新:2026-03-26