Skip to content

1.12 错误处理 ​

error 接口 ​

go
package main

import (
    "errors"
    "fmt"
)

// 创建错误
func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("除数不能为零")
    }
    return a / b, nil
}

func main() {
    // 错误检查
    result, err := divide(10, 0)
    if err != nil {
        fmt.Println("错误:", err)
        return
    }

    // 错误处理模式

    // 1. 直接返回
    if err != nil {
        return err
    }

    // 2. 包装错误
    if err != nil {
        return fmt.Errorf("处理失败:%w", err)
    }

    // 3. 记录日志
    if err != nil {
        logError(err)
    }

    // 4. 忽略错误
    result, _ = divide(10, 2)
}

func logError(err error) {
    fmt.Println("记录错误:", err)
}

自定义错误类型 ​

go
package main

import (
    "errors"
    "fmt"
    "time"
)

// 自定义错误
type ValidationError struct {
    Field   string
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("验证错误 [%s]: %s", e.Field, e.Message)
}

// 带堆栈的错误
type AppError struct {
    Code    string
    Message string
    Err     error
    Time    time.Time
}

func (e *AppError) Error() string {
    return fmt.Sprintf("[%s] %s: %v", e.Code, e.Message, e.Err)
}

func (e *AppError) Unwrap() error {
    return e.Err
}

// 错误类型判断
func validateAge(age int) error {
    if age < 0 {
        return &ValidationError{Field: "age", Message: "年龄不能为负"}
    }
    return nil
}

func main() {
    err := validateAge(-1)
    if err != nil {
        if ve, ok := err.(*ValidationError); ok {
            fmt.Printf("字段:%s, 消息:%s\n", ve.Field, ve.Message)
        }
    }

    // 哨兵错误
    var ErrNotFound = errors.New("未找到")
}

errors 包 ​

go
package main

import (
    "errors"
    "fmt"
)

var ErrNotFound = errors.New("记录未找到")

func findUser(id int) error {
    if id < 0 {
        return ErrNotFound
    }
    return nil
}

func main() {
    // errors.Is - 检查错误链
    err := findUser(-1)
    if errors.Is(err, ErrNotFound) {
        fmt.Println("输入无效")
    }

    // errors.As - 提取特定类型错误
    var ve *ValidationError
    if errors.As(err, &ve) {
        fmt.Println("字段:", ve.Field)
    }

    // errors.Join - 合并错误 (Go 1.20+)
    err1 := errors.New("错误 1")
    err2 := errors.New("错误 2")
    err3 := errors.Join(err1, err2)
    fmt.Println(err3)

    // 错误包装
    baseErr := errors.New("原始错误")
    wrappedErr := fmt.Errorf("包装:%w", baseErr)
    fmt.Println(errors.Unwrap(wrappedErr))
}

panic 与 recover ​

go
package main

import "fmt"

func main() {
    // 安全除法
    result := safeDivide(10, 0)
    fmt.Println("结果:", result)

    // recover 示例
    safeFunc()
}

func safeDivide(a, b int) (result int) {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("捕获 panic:", r)
            result = 0
        }
    }()

    if b == 0 {
        panic("除数为零")
    }
    return a / b
}

func safeFunc() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("从 panic 恢复:", r)
        }
    }()
    panic("测试 panic")
}