大家好,这里是Good Note,关注 公主号:Goodnote,专栏文章私信限时Free。本文详细介绍Golang的两种错误处理机制:error 和 panic。
文章目录
- Golang 的错误处理机制概述
- `error`
- 特点
- 代码示例
- 基本用法
- 创建 `error`
- `panic`
- 特点
- 运行时错误示例
- `defer` 和 `recover` 的结合使用
- 代码示例
- 基本用法
- 创建 `panic`
- `panic` 的执行机制
- `error` 和 `panic` 的对比
- 生产环境的建议
- 生产环境中使用 `panic` 的场景
- 启动阶段异常强制终止。
- 场景
- 示例
- 不需要捕获
- 异步 Goroutine 中的异常防护
- 场景
- 示例
- 需要捕获
- 历史文章
- MySQL数据库
- Redis
- Golang
Golang 提供两种主要的错误处理机制:
error
:处理程序员可预知、意料之中的错误,例如文件打开失败、输入不合法等。panic
:处理程序员无法预知的严重异常,例如数组越界、空指针引用等。这类错误通常是不可恢复的,可能导致程序崩溃。error
func main() {
content, err := ioutil.ReadFile("filepath")
if err != nil {
// 错误处理
// 记录错误信息
fmt.Println("Error:", err)
} else {
fmt.Println(string(content))
}
}
err == nil
,表示没有错误;否则需要对错误进行处理。error
Go 提供两种方式创建 error
:
errors.New
:import "errors"
fmt.Println(errors.New("错误"))
fmt.Errorf
:import "fmt"
fmt.Println(fmt.Errorf("错误"))
panic
panic
会中止程序运行。defer
和 recover
使用:提供有限的恢复能力。func main() {
n := 0
res := 1 / n // 引发 panic:除以零
fmt.Println(res)
}
defer
和 recover
的结合使用recover
是 Go 内置函数,用于捕获 panic
,实现部分恢复程序控制权。
func handlePanic() {
if err := recover(); err != nil {
fmt.Println("Recovered from panic:", err)
}
}
func main() {
defer handlePanic() // 在 panic 前注册 defer
n := 0
res := 1 / n // 引发 panic
fmt.Println(res) // 这行不会执行
}
defer
的执行顺序是先进后出,注册顺序很重要。panic
被捕获时,recover
会返回 panic
的错误信息。panic
通过内置函数 panic
,直接触发一个运行时错误,终止程序执行。
package main
func main() {
panic("this is a panic")
}
panic
状态,中止执行当前函数,并调用已注册的 defer
函数。panic
的执行机制当 panic
发生:
defer
会按逆序执行。recover
,程序将崩溃并打印 panic
信息。recover
的限制:
defer
中调用。panic
。defer
要在panic
之前先注册(defer必须在panic前面),否则不能捕获异常。defer
会确保即使发生 panic
,仍然可以执行资源清理逻辑。error
和 panic
的对比特性 | error |
panic |
---|---|---|
定义 | 可预期的错误 | 不可预期的严重异常 |
处理方式 | 通过返回值传递,由调用方检查和处理 | 通过 defer 和 recover 捕获 |
程序状态 | 不中断程序 | 中断程序 |
使用场景 | 文件操作失败、网络超时等正常错误 | 数组越界、空指针等致命错误 |
恢复能力 | 错误处理后可恢复 | 如果没有 recover 则无法恢复 |
总结:
error
是 Go 中主要的错误处理方式,适合处理常规错误。panic
应用于不可恢复的错误,但应谨慎使用,避免影响程序健壮性。实际开发中,使用Error会多,一些逻辑的判断,错误都会使用error,但是很少用到Panic。
以下是关于 生产环境中使用 panic
的场景及是否需要捕获 panic
:
panic
的场景在生产环境中,panic
的使用场景非常有限,通常只用于程序中无法恢复的严重错误。以下是一些实际使用 panic
的典型场景:
一般来说,常用的Web框架/任务调度系统都会在框架的出入口封装panic及其捕获逻辑(防御性编程和不可恢复的逻辑错误),程序的顶层入口函数中捕获所有未处理的 panic
,用于记录日志、释放资源或优雅退出程序。
防御性编程:库函数或 API 接收到非法输入导致程序状态不安全时,可以使用
panic
作为防御手段,明确提示调用方。
不可恢复的逻辑错误:数据结构或状态出现严重问题,如数组越界、递归深度超限等,这种错误通常不可恢复。
panic
不应影响其他请求。panic
不应导致整个系统宕机。上面是web框架在做的一些panic场景的封装,下面是两个在日常开发中,需要额外注意的情况:
启动阶段是指 运行程序时 的初始化阶段,也就是程序开始执行 main.go 文件中的代码时。
package main
import (
"fmt"
"os"
)
func loadConfig(filePath string) {
if _, err := os.Stat(filePath); os.IsNotExist(err) {
panic(fmt.Sprintf("Critical error: Config file %s is missing", filePath))
}
fmt.Println("Configuration loaded successfully.")
}
func main() {
loadConfig("missing_config.yaml") // 模拟配置文件缺失
}
不需要。
此类问题属于致命错误,无法恢复,直接让程序崩溃是合理的选择,开发者需要修复问题。
package main
import (
"fmt"
"time"
)
func safeGo(task func()) {
go func() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic in goroutine:", r)
// 此处可以添加错误日志记录逻辑或其他恢复措施
}
}()
task()
}()
}
func main() {
safeGo(func() {
panic("Task failed!") // 模拟任务失败
})
fmt.Println("Program continues running...")
time.Sleep(2 * time.Second) // 等待 Goroutine 执行完成
}
原因:
注意事项:
recover
,导致隐藏问题无法被及时发现和修复。Debug < Info < Warn < Error < Panic
MySQL数据库
Redis数据库笔记合集