Skip to content

第 13 章:错误处理

13.1 Go 的错误处理理念:没有 try-catch

Go 语言采用了一种不同于其他语言的错误处理方式,它没有 try-catch 语句,而是通过返回值来处理错误。这种设计理念的优点是:

  • 错误处理更加明确,代码更加清晰
  • 强制开发者处理错误,减少未处理错误的情况
  • 错误处理与正常逻辑分离,提高代码可读性

13.2 error 类型使用

error 接口

Go 中的错误是通过 error 接口来表示的:

go
type error interface {
    Error() string
}

返回错误

函数通常会返回一个 error 类型作为最后一个返回值:

go
func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, fmt.Errorf("division by zero")
    }
    return a / b, nil
}

处理错误

go
result, err := divide(10, 2)
if err != nil {
    fmt.Println("Error:", err)
    return
}
fmt.Println("Result:", result)

示例

go
package main

import (
    "fmt"
    "os"
)

func readFile(filename string) (string, error) {
    data, err := os.ReadFile(filename)
    if err != nil {
        return "", err
    }
    return string(data), nil
}

func main() {
    content, err := readFile("test.txt")
    if err != nil {
        fmt.Printf("Error reading file: %v\n", err)
        return
    }
    fmt.Println("File content:", content)
}

13.3 自定义错误

使用 errors.New

go
import "errors"

var ErrNotFound = errors.New("resource not found")

func findUser(id int) (User, error) {
    if id <= 0 {
        return User{}, ErrNotFound
    }
    // 查找用户
    return User{ID: id, Name: "Alice"}, nil
}

使用 fmt.Errorf

go
func processUser(id int) error {
    user, err := findUser(id)
    if err != nil {
        return fmt.Errorf("failed to process user: %w", err)
    }
    // 处理用户
    return nil
}

自定义错误类型

go
type AppError struct {
    Code    int
    Message string
}

func (e AppError) Error() string {
    return fmt.Sprintf("%d: %s", e.Code, e.Message)
}

func validateInput(input string) error {
    if input == "" {
        return AppError{Code: 400, Message: "input cannot be empty"}
    }
    return nil
}

13.4 panic 与 recover(异常处理)

panic

panic 用于处理严重错误,会导致程序终止执行:

go
func process() {
    panic("something went wrong")
    fmt.Println("This line will not execute")
}

recover

recover 用于捕获 panic,防止程序崩溃:

go
func safeProcess() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered from panic:", r)
        }
    }()
    
    panic("something went wrong")
}

func main() {
    safeProcess()
    fmt.Println("Program continues execution")
}

何时使用 panic

  • 当程序遇到无法恢复的错误时
  • 当程序逻辑出现严重错误时
  • 当函数的前置条件被违反时

实际应用

go
package main

import "fmt"

func mustDivide(a, b float64) float64 {
    if b == 0 {
        panic("division by zero")
    }
    return a / b
}

func safeDivide(a, b float64) float64 {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered:", r)
        }
    }()
    return mustDivide(a, b)
}

func main() {
    result := safeDivide(10, 0)
    fmt.Println("Result:", result) // 输出 0
    fmt.Println("Program continues")
}

© 2026 编程马·菜鸟教程 版权所有