【Go 】异常处理
1. Go 语言错误处理基础
- Go 语言尽量避免使用异常,推荐使用 返回错误 让调用者处理。
- Go 语言标准库提供
error
接口:type error interface { Error() string }
errors.New("错误信息")
创建错误对象。
package main
import (
"errors"
"fmt"
)
func hello(name string) error {
if len(name) == 0 {
return errors.New("NameError: name is empty!!")
}
fmt.Println("hello !", name)
return nil
}
func main() {
err := hello("")
if err != nil {
fmt.Println("发生错误:", err)
}
}
2. 自定义错误
- 用
errors.New()
生成错误信息 - 用
fmt.Errorf()
格式化错误信息 - 返回错误让调用者决定如何处理
package main
import (
"errors"
"fmt"
)
func divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("除数不能为0")
}
return a / b, nil
}
func main() {
result, err := divide(10, 0)
if err != nil {
fmt.Println("计算错误:", err)
} else {
fmt.Println("计算结果:", result)
}
}
3. panic
和 recover
panic
类似于 Python 的raise
,会让程序崩溃。recover
用于捕获panic
,防止程序崩溃。recover
必须在defer
语句中调用,否则无效。
package main
import "fmt"
func safeFunction() {
defer func() {
if r := recover(); r != nil {
fmt.Println("捕获到 panic:", r)
}
}()
fmt.Println("执行函数...")
panic("故意触发 panic") // 触发 panic
}
func main() {
safeFunction()
fmt.Println("程序继续执行...")
}
4. panic
与数组越界
- 数组访问越界会引发
panic
,所以要提前检查索引范围。
package main
import (
"errors"
"fmt"
)
func getElement(index int) (int, error) {
arr := [3]int{10, 20, 30}
if index < 0 || index >= len(arr) {
return 0, errors.New("索引超出范围")
}
return arr[index], nil
}
func main() {
elem, err := getElement(3)
if err != nil {
fmt.Println("错误:", err)
} else {
fmt.Println("元素:", elem)
}
}
5. defer
关键字
defer
语句用于延迟执行,常用于 释放资源、错误恢复等场景。- 多个
defer
按 先进后出(LIFO) 执行。
package main
import "fmt"
func deferTest() {
defer fmt.Println("defer 1")
defer fmt.Println("defer 2")
fmt.Println("正常执行")
}
func main() {
deferTest()
}
执行顺序:
正常执行
defer 2
defer 1
6. 处理文件操作错误
- 文件操作涉及错误处理,
os.OpenFile()
返回error
,要检查是否为nil
。
package main
import (
"fmt"
"os"
)
func openFile() {
file, err := os.OpenFile("test.txt", os.O_RDONLY, 0666)
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()
fmt.Println("文件打开成功")
}
func main() {
openFile()
}
7. recover
结合 defer
进行异常恢复
recover()
只能在defer
内部使用,否则无法捕获panic
。- 可以用
recover
拦截异常,防止整个程序崩溃。
package main
import "fmt"
func safeRun() {
defer func() {
if r := recover(); r != nil {
fmt.Println("捕获异常:", r)
}
}()
panic("这是一个 panic 例子")
}
func main() {
safeRun()
fmt.Println("程序没有崩溃,继续执行")
}
8. 手动 panic
panic()
直接终止当前函数,沿调用栈向上传播。- 通常用于 不可恢复的严重错误(如数组越界)。
package main
import "fmt"
func checkIndex(index int) {
if index < 0 {
panic("索引不能为负数")
}
fmt.Println("索引有效:", index)
}
func main() {
checkIndex(1)
checkIndex(-1) // 这里会触发 panic
}