Golang 错误类型
最后修改时间 2025 年 5 月 8 日
本教程将解释如何在 Go 中使用内置的 error
类型。我们将通过实际示例涵盖错误处理基础以及 Go 程序中正确的错误管理。
error
类型是 Go 中用于错误处理的内置接口。它是 Go 显式错误检查方法而不是异常的基石。error 接口需要一个方法:Error() string
。
在 Go 中,可能失败的函数通常将其最后一个返回值作为错误返回。约定是在函数调用后立即检查此错误值。这使得错误处理显式且可预测。
基本错误处理示例
最简单的错误处理是检查函数是否返回了错误。此示例演示了 Go 中的基本错误检查。
注意:始终在函数调用后立即处理错误。
package main import ( "errors" "fmt" ) func divide(a, b float64) (float64, error) { if b == 0 { return 0, errors.New("division by zero") } return a / b, nil } func main() { result, err := divide(10, 2) if err != nil { fmt.Println("Error:", err) return } fmt.Println("Result:", result) }
divide
函数在尝试除以零时会返回错误。调用者在继续处理结果之前会检查错误。
创建自定义错误类型
我们可以通过实现 error 接口来创建自定义错误类型。此示例展示了如何定义和使用自定义错误类型。
package main import ( "fmt" "time" ) type TimeoutError struct { Operation string Timeout time.Duration } func (e *TimeoutError) Error() string { return fmt.Sprintf("%s timed out after %v", e.Operation, e.Timeout) } func process() error { return &TimeoutError{ Operation: "database query", Timeout: 5 * time.Second, } } func main() { err := process() if err != nil { fmt.Println("Error:", err) return } fmt.Println("Operation successful") }
TimeoutError
类型通过有关操作的附加上下文实现了 error 接口。自定义错误提供更详细的错误信息。
使用 fmt.Errorf 包装错误
Go 1.13 引入了使用 fmt.Errorf
和 %w
动词进行错误包装。此示例展示了如何包装错误以保留上下文。
package main import ( "errors" "fmt" "os" ) func readConfig() error { _, err := os.ReadFile("config.json") if err != nil { return fmt.Errorf("read config: %w", err) } return nil } func main() { err := readConfig() if err != nil { fmt.Println("Error:", err) var pathErr *os.PathError if errors.As(err, &pathErr) { fmt.Println("Failed to access file:", pathErr.Path) } } }
%w
动词在添加上下文的同时包装了原始错误。errors.As
函数用于检查链中的特定错误类型。
使用 errors.Is 比较错误
errors.Is
函数用于检查错误链中的特定错误。此示例演示了使用哨兵错误进行错误比较。
package main import ( "errors" "fmt" "io" "os" ) var ErrFileNotFound = errors.New("file not found") func openFile(name string) error { _, err := os.Open(name) if err != nil { if errors.Is(err, os.ErrNotExist) { return ErrFileNotFound } return fmt.Errorf("open file: %w", err) } return nil } func main() { err := openFile("missing.txt") if errors.Is(err, ErrFileNotFound) { fmt.Println("Custom file not found error") } if err != nil { fmt.Println("Error:", err) } }
该示例定义了一个哨兵错误 ErrFileNotFound
。errors.Is
函数用于检查链中的此特定错误。
Panic 和 Recover 处理意外错误
虽然大多数错误应正常处理,但 panic 和 recover 用于处理真正特殊的情况。此示例展示了正确的 panic/recover 用法。
package main import ( "fmt" "log" ) func processTask(taskID int) { defer func() { if r := recover(); r != nil { log.Printf("Recovered from panic in task %d: %v", taskID, r) } }() if taskID == 0 { panic("invalid task ID") } fmt.Printf("Processing task %d\n", taskID) } func main() { processTask(1) processTask(0) // This will panic processTask(2) fmt.Println("All tasks processed") }
延迟的 recover 函数可以优雅地处理 panic。这种模式对于必须在错误后继续运行的服务器应用程序很有用。
来源
本教程涵盖了 Go 中的 error
类型,并通过错误处理、自定义错误、包装、比较和恢复的实际示例进行了说明。