golang 错误处理和异常处理

在 Golang 中,错误处理异常处理是两个不同的概念,分别用于处理不同类型的问题。Golang 的设计哲学强调显式错误处理,而异常机制主要用于不可恢复的严重问题。以下是它们的详细介绍:


1. 错误处理

在 Golang 中,错误处理是通过返回值实现的。函数通常返回一个 error 类型的值,调用者需要检查该值是否为 nil 来判断是否发生了错误。

1.1 基本错误处理模式

函数返回 (result, error),调用者通过检查 error 来决定如何处理。

示例:

package main

import (
    "errors"
    "fmt"
)

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("division by zero") // 返回错误
    }
    return a / b, nil // 正常返回结果
}

func main() {
    result, err := divide(10, 0) // 调用函数
    if err != nil {
        fmt.Println("Error:", err) // 错误处理
    } else {
        fmt.Println("Result:", result)
    }
}

运行结果

Error: division by zero

1.2 自定义错误

Golang 支持创建自定义错误类型,通过实现 error 接口的 Error() 方法来自定义错误信息。

示例:

package main

import "fmt"

// 自定义错误类型
type MyError struct {
    Code    int
    Message string
}

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

func doSomething() error {
    return &MyError{Code: 404, Message: "Resource not found"} // 返回自定义错误
}

func main() {
    err := doSomething()
    if err != nil {
        fmt.Println(err) // 打印自定义错误
    }
}

运行结果

Error 404: Resource not found

1.3 使用 fmt.Errorf 格式化错误

Golang 提供了 fmt.Errorf 来生成格式化的错误信息。

示例:

package main

import (
    "fmt"
)

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, fmt.Errorf("cannot divide %d by zero", a) // 格式化错误信息
    }
    return a / b, nil
}

func main() {
    _, err := divide(10, 0)
    if err != nil {
        fmt.Println("Error:", err)
    }
}

运行结果

Error: cannot divide 10 by zero

1.4 errors.Iserrors.As

在 Golang 1.13+ 中,errors 包增加了 errors.Iserrors.As 方法,用于检查和处理嵌套错误。

示例:

package main

import (
    "errors"
    "fmt"
)

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

func findResource(id int) error {
    if id == 0 {
        return fmt.Errorf("resource error: %w", ErrNotFound) // 嵌套错误
    }
    return nil
}

func main() {
    err := findResource(0)
    if errors.Is(err, ErrNotFound) { // 检查是否是 ErrNotFound 错误
        fmt.Println("Resource not found")
    } else {
        fmt.Println("Other error:", err)
    }
}

运行结果

Resource not found

2. 异常处理

Golang 的异常处理是通过 panicrecover 实现的。它们主要用于处理程序中的不可恢复错误,例如逻辑错误或严重的运行时问题。

2.1 panic

  • panic 会立即停止当前函数的执行,并向调用栈上传播,最终导致程序崩溃。
  • 通常用于不可恢复的错误,例如数组越界、空指针访问等。

示例:

package main

func main() {
    panic("something went wrong") // 触发 panic
}

运行结果

panic: something went wrong

goroutine 1 [running]:
main.main()
    /path/to/main.go:4 +0x39
exit status 2

2.2 recover

  • recover 用于捕获 panic,从而恢复程序的正常运行。
  • 必须在 defer 中调用,否则无法捕获 panic

示例:

package main

import "fmt"

func main() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered from panic:", r) // 捕获 panic
        }
    }()

    panic("something went wrong") // 触发 panic
    fmt.Println("This will not be printed")
}

运行结果

Recovered from panic: something went wrong

2.3 panic 和 recover 的使用场景

  • panic:用于不可恢复的错误,例如程序的内部逻辑错误。
  • recover:用于捕获 panic,从而在某些情况下恢复程序的运行。

示例:在子协程中捕获 panic

package main

import (
    "fmt"
    "time"
)

func safeGo(f func()) {
    go func() {
        defer func() {
            if r := recover(); r != nil {
                fmt.Println("Recovered from panic:", r)
            }
        }()
        f()
    }()
}

func main() {
    safeGo(func() {
        panic("something went wrong in goroutine") // 子协程触发 panic
    })

    time.Sleep(1 * time.Second) // 确保主协程不会过早退出
    fmt.Println("Main function continues")
}

运行结果

Recovered from panic: something went wrong in goroutine
Main function continues

3. 错误处理 vs 异常处理

特性 错误处理 异常处理
机制 函数返回值 (error) panicrecover
使用场景 常见的业务逻辑错误 程序中不可恢复的严重错误
处理方式 显式检查错误 隐式捕获(通过 recover
对程序的影响 不影响程序的正常运行 未捕获的 panic 会导致程序崩溃
推荐使用场景 推荐用于大多数场景 仅用于异常或不可恢复的错误

4. 总结

  1. 错误处理是 Golang 的主流方式,通常通过返回 error 值让调用者显式处理。
  2. 异常处理panicrecover)仅用于不可恢复的错误,应该谨慎使用。
  3. 在 Golang 中,更推荐使用显式的错误处理方式,而不是依赖异常机制。
  4. 对于子协程中的 panic,可以通过 recover 捕获,避免影响主程序的运行。
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容