目录
1. panic 异常
panic
是 Go 程序在 运行时出现严重错误 时触发的异常机制。
常见触发原因:除零错误、数组/切片越界、空指针引用、明确调用 panic()
当 panic
发生时:
程序会立即中断正常执行流程;
先执行当前函数的
defer
语句;再沿着调用栈向上逐层返回,并依次执行各层函数的
defer
;如果在最顶层(
main
函数)仍未被捕获,则程序崩溃并打印错误信息和调用栈。
package main
import "fmt"
func Division(num1 int, num2 int) int {
defer fmt.Println("Division defer...") // 会执行
return num1 / num2
}
func main() {
defer fmt.Println("main defer...") // 会执行
// panic 异常:除零
result := Division(10, 0)
fmt.Printf("result = %d\n", result) // 不会执行
fmt.Println("other code...") // 不会执行
}
/*
Division defer...
main defer...
panic: runtime error: integer divide by zero
goroutine 1 [running]:
main.Division(0x10255ed40?, 0x14000096000?)
/Users/mac/Desktop/test_go/main.go:7 +0x88
main.main()
/Users/mac/Desktop/test_go/main.go:13 +0x64
进程 已完成,退出代码为 2
*/
2. recover 捕获异常
1.
recover
的作用
recover
是 Go 内建函数,用于 捕获 panic
,防止程序直接崩溃。
它必须写在 defer
延迟调用的函数里,否则不起作用。
触发 panic
后,recover
会:
返回
panic
的值(通常是error
或string
);使程序从
panic
中恢复,继续执行后续代码。
2. 使用
recover
一般写在匿名函数的 defer
里,这样,即使发生 panic
,程序也不会崩溃。
defer func() {
if r := recover(); r != nil {
fmt.Println("捕获到 panic:", r)
}
}()
package main
import (
"errors"
"fmt"
)
func Division(num1, num2 int) (res int, err error) {
defer func() {
if r := recover(); r != nil {
err = errors.New(fmt.Sprintf("panic: %v", r))
}
}()
return num1 / num2, nil
}
func main() {
result, err := Division(10, 0)
if err != nil {
fmt.Printf("division operation error, err = %v\n", err)
} else {
fmt.Printf("result = %d\n", result)
}
fmt.Println("main 函数后续代码仍然会执行")
}
// division operation error, err = panic: runtime error: integer divide by zero
// main 函数后续代码仍然会执行
3. 自定义错误
- 错误 (
error
):用于描述可预期、可恢复的问题(比如:文件不存在、网络超时)。 - 异常 (
panic
):用于描述不可恢复的严重问题,或需要强制中断的情况。 errors.New
:快速创建一个自定义错误值。panic(errors.New(...))
:主动触发异常。recover
:捕获panic
,让程序继续运行。
1. error 接口
Go 中所有错误都实现了内建的 error
接口,这意味着任何类型只要有 Error() string
方法,就可以作为 error
使用。
type error interface {
Error() string
}
2. 创建错误
// 最常见的方式是用 errors.New
import "errors"
err := errors.New("something went wrong")
fmt.Println(err) // 输出: something went wrong
3. 使用
panic
主动触发异常
除了运行时错误(除零、数组越界等),我们也可以 主动触发 panic,并传入一个 error
类型:
package main
import (
"errors"
"fmt"
)
func CheckAge(age int) {
if age < 0 {
panic(errors.New("年龄不能是负数"))
}
fmt.Println("合法年龄:", age)
}
func main() {
CheckAge(20)
CheckAge(-5) // 会触发 panic
fmt.Println("main 后续代码") // 不会执行
}
// 合法年龄: 20
// panic: 年龄不能是负数
4. 结合
recover
进行捕获
通常不会让 panic
直接终止程序,而是配合 recover
做 容错处理:
package main
import (
"errors"
"fmt"
)
func CheckAge(age int) {
defer func() {
if r := recover(); r != nil {
fmt.Println("捕获到错误", r)
}
}()
if age < 0 {
panic(errors.New("年龄不能是负数"))
}
fmt.Println("合法年龄:", age)
}
func main() {
CheckAge(20)
CheckAge(-5) // 会触发 panic
fmt.Println("main 后续代码") // 不会执行
}
/*
合法年龄: 20
捕获到错误 年龄不能是负数
main 后续代码
*/