This commit is contained in:
2025-08-24 11:24:52 +08:00
parent ec23aa5c26
commit 61e51ad014
12 changed files with 11554 additions and 4 deletions

View File

@@ -0,0 +1,957 @@
/*
01-basic-errors.go - Go 语言基础错误处理详解
学习目标:
1. 理解 Go 语言的错误处理哲学
2. 掌握 error 接口的使用
3. 学会基本的错误处理模式
4. 了解错误传播和包装
5. 掌握错误处理的最佳实践
知识点:
- error 接口的定义和实现
- 错误的创建和返回
- 错误检查和处理
- 错误传播和包装
- 错误处理的惯用法
- 错误信息的设计
*/
package main
import (
"crypto/rand"
"encoding/json"
"errors"
"fmt"
"os"
"strings"
"sync"
"time"
)
func main() {
fmt.Println("=== Go 语言基础错误处理详解 ===\\n")
// 演示错误接口的基本概念
demonstrateErrorInterface()
// 演示错误的创建方式
demonstrateErrorCreation()
// 演示错误检查和处理
demonstrateErrorHandling()
// 演示错误传播
demonstrateErrorPropagation()
// 演示错误包装
demonstrateErrorWrapping()
// 演示错误处理模式
demonstrateErrorPatterns()
// 演示实际应用场景
demonstratePracticalExamples()
}
// demonstrateErrorInterface 演示错误接口的基本概念
func demonstrateErrorInterface() {
fmt.Println("1. 错误接口的基本概念:")
// error 接口的定义
fmt.Printf(" error 接口的定义:\\n")
fmt.Printf(" type error interface {\\n")
fmt.Printf(" Error() string\\n")
fmt.Printf(" }\\n")
fmt.Printf("\\n")
fmt.Printf(" 错误处理的特点:\\n")
fmt.Printf(" - 错误是值,可以像其他值一样传递\\n")
fmt.Printf(" - 使用多返回值模式处理错误\\n")
fmt.Printf(" - 显式错误检查,不隐藏错误\\n")
fmt.Printf(" - 错误应该被处理,不应该被忽略\\n")
fmt.Printf(" - 错误信息应该清晰、有用\\n")
// 基本错误示例
fmt.Printf(" 基本错误示例:\\n")
// 成功的情况
result, err := divide(10, 2)
if err != nil {
fmt.Printf(" 错误: %v\\n", err)
} else {
fmt.Printf(" 10 / 2 = %.2f\\n", result)
}
// 错误的情况
result, err = divide(10, 0)
if err != nil {
fmt.Printf(" 错误: %v\\n", err)
} else {
fmt.Printf(" 10 / 0 = %.2f\\n", result)
}
// nil 错误检查
fmt.Printf(" nil 错误检查:\\n")
var nilError error
fmt.Printf(" nil 错误: %v\\n", nilError)
fmt.Printf(" nil 错误 == nil: %t\\n", nilError == nil)
// 错误比较
fmt.Printf(" 错误比较:\\n")
err1 := errors.New("相同的错误")
err2 := errors.New("相同的错误")
fmt.Printf(" err1 == err2: %t (内容相同但不是同一个对象)\\n", err1 == err2)
fmt.Printf(" err1.Error() == err2.Error(): %t\\n", err1.Error() == err2.Error())
fmt.Println()
}
// demonstrateErrorCreation 演示错误的创建方式
func demonstrateErrorCreation() {
fmt.Println("2. 错误的创建方式:")
// 使用 errors.New 创建错误
fmt.Printf(" 使用 errors.New 创建错误:\\n")
err1 := errors.New("这是一个简单的错误")
fmt.Printf(" 错误1: %v\\n", err1)
// 使用 fmt.Errorf 创建格式化错误
fmt.Printf(" 使用 fmt.Errorf 创建格式化错误:\\n")
username := "alice"
err2 := fmt.Errorf("用户 %s 不存在", username)
fmt.Printf(" 错误2: %v\\n", err2)
// 创建带有更多信息的错误
age := -5
err3 := fmt.Errorf("无效的年龄值: %d (年龄必须大于0)", age)
fmt.Printf(" 错误3: %v\\n", err3)
// 使用预定义错误
fmt.Printf(" 使用预定义错误:\\n")
predefinedErrors := []error{
ErrInvalidInput,
ErrNotFound,
ErrPermissionDenied,
ErrTimeout,
}
for i, err := range predefinedErrors {
fmt.Printf(" 预定义错误%d: %v\\n", i+1, err)
}
// 条件性错误创建
fmt.Printf(" 条件性错误创建:\\n")
testValues := []int{-1, 0, 5, 101}
for _, value := range testValues {
if err := validateAge(value); err != nil {
fmt.Printf(" 验证年龄 %d: %v\\n", value, err)
} else {
fmt.Printf(" 验证年龄 %d: 有效\\n", value)
}
}
fmt.Println()
}
// demonstrateErrorHandling 演示错误检查和处理
func demonstrateErrorHandling() {
fmt.Println("3. 错误检查和处理:")
// 基本错误检查模式
fmt.Printf(" 基本错误检查模式:\\n")
// 立即检查错误
content, err := readFile("example.txt")
if err != nil {
fmt.Printf(" 读取文件失败: %v\\n", err)
} else {
fmt.Printf(" 文件内容: %s\\n", content)
}
// 多个操作的错误处理
fmt.Printf(" 多个操作的错误处理:\\n")
err = performMultipleOperations()
if err != nil {
fmt.Printf(" 多个操作失败: %v\\n", err)
} else {
fmt.Printf(" 所有操作成功完成\\n")
}
// 错误类型检查
fmt.Printf(" 错误类型检查:\\n")
testOperations := []func() error{
func() error { return ErrNotFound },
func() error { return ErrPermissionDenied },
func() error { return fmt.Errorf("未知错误") },
func() error { return nil },
}
for i, op := range testOperations {
err := op()
fmt.Printf(" 操作%d: ", i+1)
handleSpecificError(err)
}
// 错误恢复
fmt.Printf(" 错误恢复:\\n")
data, err := fetchDataWithRetry("https://api.example.com/data", 3)
if err != nil {
fmt.Printf(" 获取数据失败: %v\\n", err)
} else {
fmt.Printf(" 获取数据成功: %s\\n", data)
}
// 部分失败处理
fmt.Printf(" 部分失败处理:\\n")
results, errors := processBatch([]string{"item1", "item2", "invalid", "item4"})
fmt.Printf(" 成功处理: %v\\n", results)
fmt.Printf(" 处理错误: %v\\n", errors)
fmt.Println()
}
// demonstrateErrorPropagation 演示错误传播
func demonstrateErrorPropagation() {
fmt.Println("4. 错误传播:")
// 简单错误传播
fmt.Printf(" 简单错误传播:\\n")
result, err := calculateTotal([]float64{10.5, 20.0, -5.0, 15.5})
if err != nil {
fmt.Printf(" 计算总和失败: %v\\n", err)
} else {
fmt.Printf(" 总和: %.2f\\n", result)
}
// 带上下文的错误传播
fmt.Printf(" 带上下文的错误传播:\\n")
user, err := getUserProfile("nonexistent_user")
if err != nil {
fmt.Printf(" 获取用户资料失败: %v\\n", err)
} else {
fmt.Printf(" 用户资料: %+v\\n", user)
}
// 错误链
fmt.Printf(" 错误链:\\n")
err = processOrder("invalid_order_id")
if err != nil {
fmt.Printf(" 处理订单失败: %v\\n", err)
// 展示错误链
fmt.Printf(" 错误链分析:\\n")
printErrorChain(err, " ")
}
// 选择性错误传播
fmt.Printf(" 选择性错误传播:\\n")
results := []string{}
errors := []error{}
items := []string{"valid1", "invalid", "valid2", "error", "valid3"}
for _, item := range items {
result, err := processItem(item)
if err != nil {
errors = append(errors, fmt.Errorf("处理 %s 失败: %w", item, err))
} else {
results = append(results, result)
}
}
fmt.Printf(" 成功结果: %v\\n", results)
if len(errors) > 0 {
fmt.Printf(" 错误列表:\\n")
for _, err := range errors {
fmt.Printf(" - %v\\n", err)
}
}
fmt.Println()
}
// demonstrateErrorWrapping 演示错误包装
func demonstrateErrorWrapping() {
fmt.Println("5. 错误包装:")
// 基本错误包装
fmt.Printf(" 基本错误包装:\\n")
originalErr := errors.New("原始错误")
wrappedErr := fmt.Errorf("包装错误: %w", originalErr)
fmt.Printf(" 原始错误: %v\\n", originalErr)
fmt.Printf(" 包装错误: %v\\n", wrappedErr)
// 错误解包
fmt.Printf(" 错误解包:\\n")
unwrappedErr := errors.Unwrap(wrappedErr)
fmt.Printf(" 解包后的错误: %v\\n", unwrappedErr)
fmt.Printf(" 解包后是否为原始错误: %t\\n", unwrappedErr == originalErr)
// 错误检查 (errors.Is)
fmt.Printf(" 错误检查 (errors.Is):\\n")
fmt.Printf(" wrappedErr 是否为 originalErr: %t\\n", errors.Is(wrappedErr, originalErr))
fmt.Printf(" wrappedErr 是否为 ErrNotFound: %t\\n", errors.Is(wrappedErr, ErrNotFound))
// 多层包装
fmt.Printf(" 多层包装:\\n")
baseErr := ErrNotFound
level1Err := fmt.Errorf("数据库查询失败: %w", baseErr)
level2Err := fmt.Errorf("用户服务错误: %w", level1Err)
level3Err := fmt.Errorf("API 请求失败: %w", level2Err)
fmt.Printf(" 多层包装错误: %v\\n", level3Err)
fmt.Printf(" 是否包含 ErrNotFound: %t\\n", errors.Is(level3Err, ErrNotFound))
// 错误类型断言 (errors.As)
fmt.Printf(" 错误类型断言 (errors.As):\\n")
customErr := &CustomError{
Code: 404,
Message: "资源未找到",
Details: "请求的用户ID不存在",
}
wrappedCustomErr := fmt.Errorf("处理请求失败: %w", customErr)
var targetErr *CustomError
if errors.As(wrappedCustomErr, &targetErr) {
fmt.Printf(" 找到自定义错误: Code=%d, Message=%s\\n",
targetErr.Code, targetErr.Message)
}
fmt.Println()
}
// demonstrateErrorPatterns 演示错误处理模式
func demonstrateErrorPatterns() {
fmt.Println("6. 错误处理模式:")
// 哨兵错误模式
fmt.Printf(" 哨兵错误模式:\\n")
_, err := findUser("nonexistent")
if errors.Is(err, ErrUserNotFound) {
fmt.Printf(" 用户不存在,使用默认用户\\n")
} else if err != nil {
fmt.Printf(" 查找用户时发生其他错误: %v\\n", err)
}
// 错误类型模式
fmt.Printf(" 错误类型模式:\\n")
err = performNetworkOperation()
var netErr *NetworkError
if errors.As(err, &netErr) {
if netErr.Temporary {
fmt.Printf(" 临时网络错误,可以重试: %v\\n", netErr)
} else {
fmt.Printf(" 永久网络错误: %v\\n", netErr)
}
}
// 不透明错误模式
fmt.Printf(" 不透明错误模式:\\n")
err = callExternalAPI()
if err != nil {
fmt.Printf(" 外部API调用失败: %v\\n", err)
// 不检查具体错误类型,统一处理
}
// 错误聚合模式
fmt.Printf(" 错误聚合模式:\\n")
validator := NewValidator()
validator.ValidateRequired("name", "")
validator.ValidateEmail("email", "invalid-email")
validator.ValidateRange("age", -5, 0, 120)
if validator.HasErrors() {
fmt.Printf(" 验证失败:\\n")
for _, err := range validator.Errors() {
fmt.Printf(" - %v\\n", err)
}
}
// 错误恢复模式
fmt.Printf(" 错误恢复模式:\\n")
result := performWithFallback()
fmt.Printf(" 操作结果: %s\\n", result)
// 错误重试模式
fmt.Printf(" 错误重试模式:\\n")
data, err := retryOperation(func() (string, error) {
// 模拟不稳定的操作
if len(fmt.Sprintf("%d", rand.Int()))%3 == 0 {
return "成功数据", nil
}
return "", errors.New("临时失败")
}, 3)
if err != nil {
fmt.Printf(" 重试操作最终失败: %v\\n", err)
} else {
fmt.Printf(" 重试操作成功: %s\\n", data)
}
fmt.Println()
}
// demonstratePracticalExamples 演示实际应用场景
func demonstratePracticalExamples() {
fmt.Println("7. 实际应用场景:")
// 文件操作错误处理
fmt.Printf(" 文件操作错误处理:\\n")
content, err := safeReadFile("config.json")
if err != nil {
fmt.Printf(" 读取配置文件失败: %v\\n", err)
} else {
fmt.Printf(" 配置内容: %s\\n", content)
}
// 网络请求错误处理
fmt.Printf(" 网络请求错误处理:\\n")
response, err := httpGet("https://api.example.com/users/1")
if err != nil {
fmt.Printf(" HTTP请求失败: %v\\n", err)
} else {
fmt.Printf(" HTTP响应: %s\\n", response)
}
// 数据库操作错误处理
fmt.Printf(" 数据库操作错误处理:\\n")
user := User{ID: 1, Name: "Alice", Email: "alice@example.com"}
err = saveUser(user)
if err != nil {
fmt.Printf(" 保存用户失败: %v\\n", err)
} else {
fmt.Printf(" 用户保存成功\\n")
}
// JSON 解析错误处理
fmt.Printf(" JSON 解析错误处理:\\n")
jsonData := `{"name": "Bob", "age": "invalid"}`
user, err = parseUser(jsonData)
if err != nil {
fmt.Printf(" JSON解析失败: %v\\n", err)
} else {
fmt.Printf(" 解析用户: %+v\\n", user)
}
// 业务逻辑错误处理
fmt.Printf(" 业务逻辑错误处理:\\n")
account := BankAccount{Balance: 100.0}
err = account.Withdraw(150.0)
if err != nil {
fmt.Printf(" 取款失败: %v\\n", err)
} else {
fmt.Printf(" 取款成功,余额: %.2f\\n", account.Balance)
}
// 并发错误处理
fmt.Printf(" 并发错误处理:\\n")
results, errors := processConcurrently([]string{"task1", "task2", "error_task", "task4"})
fmt.Printf(" 并发处理结果: %v\\n", results)
if len(errors) > 0 {
fmt.Printf(" 并发处理错误:\\n")
for i, err := range errors {
if err != nil {
fmt.Printf(" 任务%d错误: %v\\n", i, err)
}
}
}
fmt.Println()
}
// ========== 类型定义和辅助函数 ==========
// 预定义错误
var (
ErrInvalidInput = errors.New("输入无效")
ErrNotFound = errors.New("未找到")
ErrPermissionDenied = errors.New("权限被拒绝")
ErrTimeout = errors.New("操作超时")
ErrUserNotFound = errors.New("用户未找到")
)
// CustomError 自定义错误类型
type CustomError struct {
Code int
Message string
Details string
}
func (e *CustomError) Error() string {
return fmt.Sprintf("错误 %d: %s (%s)", e.Code, e.Message, e.Details)
}
// NetworkError 网络错误类型
type NetworkError struct {
Op string
URL string
Temporary bool
Err error
}
func (e *NetworkError) Error() string {
return fmt.Sprintf("网络错误 %s %s: %v", e.Op, e.URL, e.Err)
}
// User 用户结构
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age"`
}
// BankAccount 银行账户
type BankAccount struct {
Balance float64
}
func (ba *BankAccount) Withdraw(amount float64) error {
if amount <= 0 {
return fmt.Errorf("取款金额必须大于0实际: %.2f", amount)
}
if amount > ba.Balance {
return fmt.Errorf("余额不足: 需要 %.2f,可用 %.2f", amount, ba.Balance)
}
ba.Balance -= amount
return nil
}
// Validator 验证器
type Validator struct {
errors []error
}
func NewValidator() *Validator {
return &Validator{errors: make([]error, 0)}
}
func (v *Validator) ValidateRequired(field, value string) {
if value == "" {
v.errors = append(v.errors, fmt.Errorf("字段 %s 是必需的", field))
}
}
func (v *Validator) ValidateEmail(field, value string) {
if value != "" && !strings.Contains(value, "@") {
v.errors = append(v.errors, fmt.Errorf("字段 %s 不是有效的邮箱地址", field))
}
}
func (v *Validator) ValidateRange(field string, value, min, max int) {
if value < min || value > max {
v.errors = append(v.errors, fmt.Errorf("字段 %s 必须在 %d 到 %d 之间,实际: %d", field, min, max, value))
}
}
func (v *Validator) HasErrors() bool {
return len(v.errors) > 0
}
func (v *Validator) Errors() []error {
return v.errors
}
// ========== 辅助函数 ==========
// divide 除法运算
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("除数不能为零")
}
return a / b, nil
}
// validateAge 验证年龄
func validateAge(age int) error {
if age < 0 {
return fmt.Errorf("年龄不能为负数: %d", age)
}
if age > 150 {
return fmt.Errorf("年龄不能超过150: %d", age)
}
return nil
}
// readFile 读取文件
func readFile(filename string) (string, error) {
// 模拟文件读取
if filename == "example.txt" {
return "", fmt.Errorf("文件 %s 不存在", filename)
}
return "文件内容", nil
}
// performMultipleOperations 执行多个操作
func performMultipleOperations() error {
// 模拟多个操作
operations := []func() error{
func() error { return nil }, // 成功
func() error { return nil }, // 成功
func() error { return errors.New("第三个操作失败") }, // 失败
}
for i, op := range operations {
if err := op(); err != nil {
return fmt.Errorf("操作 %d 失败: %w", i+1, err)
}
}
return nil
}
// handleSpecificError 处理特定错误
func handleSpecificError(err error) {
if err == nil {
fmt.Printf("成功\\n")
return
}
switch {
case errors.Is(err, ErrNotFound):
fmt.Printf("资源未找到\\n")
case errors.Is(err, ErrPermissionDenied):
fmt.Printf("权限不足\\n")
default:
fmt.Printf("未知错误: %v\\n", err)
}
}
// fetchDataWithRetry 带重试的数据获取
func fetchDataWithRetry(url string, maxRetries int) (string, error) {
var lastErr error
for i := 0; i < maxRetries; i++ {
// 模拟网络请求
if rand.Float32() < 0.3 { // 30% 成功率
return fmt.Sprintf("数据来自 %s", url), nil
}
lastErr = fmt.Errorf("请求 %s 失败 (尝试 %d/%d)", url, i+1, maxRetries)
time.Sleep(100 * time.Millisecond) // 重试延迟
}
return "", fmt.Errorf("重试 %d 次后仍然失败: %w", maxRetries, lastErr)
}
// processBatch 批量处理
func processBatch(items []string) ([]string, []error) {
var results []string
var errors []error
for _, item := range items {
if item == "invalid" {
errors = append(errors, fmt.Errorf("无效项目: %s", item))
} else {
results = append(results, fmt.Sprintf("处理后的%s", item))
}
}
return results, errors
}
// calculateTotal 计算总和
func calculateTotal(values []float64) (float64, error) {
total := 0.0
for i, value := range values {
if value < 0 {
return 0, fmt.Errorf("索引 %d 的值不能为负数: %.2f", i, value)
}
total += value
}
return total, nil
}
// getUserProfile 获取用户资料
func getUserProfile(username string) (*User, error) {
// 模拟数据库查询
if username == "nonexistent_user" {
return nil, fmt.Errorf("获取用户资料失败: %w", ErrUserNotFound)
}
return &User{
ID: 1,
Name: username,
Email: username + "@example.com",
}, nil
}
// processOrder 处理订单
func processOrder(orderID string) error {
// 模拟订单处理链
if err := validateOrder(orderID); err != nil {
return fmt.Errorf("处理订单 %s 失败: %w", orderID, err)
}
return nil
}
// validateOrder 验证订单
func validateOrder(orderID string) error {
if orderID == "invalid_order_id" {
if err := checkOrderExists(orderID); err != nil {
return fmt.Errorf("订单验证失败: %w", err)
}
}
return nil
}
// checkOrderExists 检查订单是否存在
func checkOrderExists(orderID string) error {
return fmt.Errorf("数据库查询失败: %w", ErrNotFound)
}
// printErrorChain 打印错误链
func printErrorChain(err error, indent string) {
if err == nil {
return
}
fmt.Printf("%s- %v\\n", indent, err)
if unwrapped := errors.Unwrap(err); unwrapped != nil {
printErrorChain(unwrapped, indent+" ")
}
}
// processItem 处理项目
func processItem(item string) (string, error) {
switch item {
case "invalid":
return "", ErrInvalidInput
case "error":
return "", errors.New("处理错误")
default:
return fmt.Sprintf("处理后的%s", item), nil
}
}
// findUser 查找用户
func findUser(username string) (*User, error) {
if username == "nonexistent" {
return nil, ErrUserNotFound
}
return &User{Name: username}, nil
}
// performNetworkOperation 执行网络操作
func performNetworkOperation() error {
return &NetworkError{
Op: "GET",
URL: "https://api.example.com",
Temporary: true,
Err: errors.New("连接超时"),
}
}
// callExternalAPI 调用外部API
func callExternalAPI() error {
return errors.New("外部服务不可用")
}
// performWithFallback 带回退的操作
func performWithFallback() string {
// 尝试主要操作
if err := primaryOperation(); err != nil {
// 主要操作失败,使用回退
return fallbackOperation()
}
return "主要操作成功"
}
// primaryOperation 主要操作
func primaryOperation() error {
return errors.New("主要操作失败")
}
// fallbackOperation 回退操作
func fallbackOperation() string {
return "回退操作成功"
}
// retryOperation 重试操作
func retryOperation(op func() (string, error), maxRetries int) (string, error) {
var lastErr error
for i := 0; i < maxRetries; i++ {
result, err := op()
if err == nil {
return result, nil
}
lastErr = err
fmt.Printf(" 尝试 %d/%d 失败: %v\\n", i+1, maxRetries, err)
if i < maxRetries-1 {
time.Sleep(100 * time.Millisecond)
}
}
return "", fmt.Errorf("重试 %d 次后失败: %w", maxRetries, lastErr)
}
// safeReadFile 安全读取文件
func safeReadFile(filename string) (string, error) {
// 模拟文件读取
switch filename {
case "config.json":
return "", fmt.Errorf("读取文件 %s 失败: %w", filename, os.ErrNotExist)
default:
return "文件内容", nil
}
}
// httpGet HTTP GET 请求
func httpGet(url string) (string, error) {
// 模拟HTTP请求
if strings.Contains(url, "example.com") {
return "", &NetworkError{
Op: "GET",
URL: url,
Temporary: false,
Err: errors.New("域名解析失败"),
}
}
return "HTTP响应内容", nil
}
// saveUser 保存用户
func saveUser(user User) error {
// 模拟数据库保存
if user.Email == "" {
return fmt.Errorf("保存用户失败: %w", ErrInvalidInput)
}
return nil
}
// parseUser 解析用户JSON
func parseUser(jsonData string) (User, error) {
var user User
if err := json.Unmarshal([]byte(jsonData), &user); err != nil {
return User{}, fmt.Errorf("解析用户JSON失败: %w", err)
}
return user, nil
}
// processConcurrently 并发处理
func processConcurrently(tasks []string) ([]string, []error) {
var wg sync.WaitGroup
results := make([]string, len(tasks))
errors := make([]error, len(tasks))
for i, task := range tasks {
wg.Add(1)
go func(index int, taskName string) {
defer wg.Done()
// 模拟任务处理
if strings.Contains(taskName, "error") {
errors[index] = fmt.Errorf("任务 %s 处理失败", taskName)
} else {
results[index] = fmt.Sprintf("处理后的%s", taskName)
}
}(i, task)
}
wg.Wait()
return results, errors
}
/*
运行这个程序:
go run 01-basic-errors.go
学习要点:
1. Go 语言使用显式错误处理,错误是值
2. error 接口只有一个 Error() string 方法
3. 使用多返回值模式处理错误
4. 错误应该被检查和处理,不应该被忽略
5. 错误信息应该清晰、有用、包含上下文
错误处理的特点:
1. 显式性:错误必须被显式检查
2. 简单性error 接口设计简单
3. 组合性:错误可以被包装和组合
4. 传播性:错误可以在调用栈中传播
5. 灵活性:支持多种错误处理模式
错误创建方式:
1. errors.New():创建简单错误
2. fmt.Errorf():创建格式化错误
3. 自定义错误类型:实现 error 接口
4. 预定义错误:定义常用错误变量
5. 错误包装:使用 %w 动词包装错误
错误检查模式:
1. 立即检查if err != nil { ... }
2. 错误传播return err 或 return fmt.Errorf("...: %w", err)
3. 错误类型检查errors.Is() 和 errors.As()
4. 错误恢复:提供默认值或回退方案
5. 错误聚合:收集多个错误
错误处理模式:
1. 哨兵错误:预定义的错误值
2. 错误类型:自定义错误结构体
3. 不透明错误:不检查具体错误类型
4. 错误包装:添加上下文信息
5. 错误聚合:收集和批量处理错误
最佳实践:
1. 错误信息应该小写开头,不以标点结尾
2. 错误信息应该包含足够的上下文
3. 使用错误包装传播上下文
4. 不要忽略错误,至少要记录日志
5. 在适当的层级处理错误
常见陷阱:
1. 忽略错误返回值
2. 错误信息不够清晰
3. 过度包装错误
4. 不适当的错误类型检查
5. 在错误处理中引入新的错误
性能考虑:
1. 错误创建有一定开销
2. 错误包装会增加内存使用
3. 错误检查是必要的开销
4. 避免在热点路径创建复杂错误
5. 合理使用预定义错误
注意事项:
1. nil 错误表示没有错误
2. 错误比较使用 == 或 errors.Is()
3. 错误类型断言使用 errors.As()
4. 错误包装使用 fmt.Errorf() 和 %w
5. 错误解包使用 errors.Unwrap()
*/