Go 错误处理 panic & recover

105 阅读2分钟

「这是我参与2022首次更文挑战的第8天,活动详情查看:2022首次更文挑战

panic 和 recover 是 Go 语言中的内置函数,和 defer有紧密的联系

panic

  • panic 能够改变程序的控制流, 调用 panic 后会立刻停止执行当前函数的剩余代码, 并在当前 Goroutine 中递归执行调用方的 defer
  • panic 用于不可恢复的错误
  • panic 退出前会执行 defer 指定内容 在这里插入图片描述

现象

  • panic 只会触发当前 Goroutine 的 defer
  • panic 运行在 defer 嵌套中多次调用

测试代码

func TestPanic(t *testing.T) {
	defer fmt.Println("in main")
	go func() {
		defer fmt.Println("in  goroutine")
		panic("")
	}()
	time.Sleep(1 * time.Second)
	defer fmt.Println("in end main")
}

运行结果

in  goroutine
panic: 

goroutine 7 [running]:
GoProject/src/main/gobase/panic_recover.TestPanic.func1()
	D:/GoProject/src/main/gobase/panic_recover/panic_recover_test.go:25 +0x9c
created by GoProject/src/main/gobase/panic_recover.TestPanic
	D:/GoProject/src/main/gobase/panic_recover/panic_recover_test.go:23 +0xc5

可以看到 我们运行这段代码会发现 mian 函数中 的 defer 语句并没有执行,执行了当前 Gorountine 中的 defer

panic 和 os.Exit 的区别

在这里插入图片描述

recover

recover 可以中止 panic 造成的程序崩溃, 它是一个只能在 defer 中发挥作用的函数,其他的作用域中调用不会发挥作用。

  • recover 只有发生 panic 只会调用之后才会生效,如果 recover 在 panic 之前调用,并不满足生效条件。
测试代码
func  TestRecover(t *testing.T)  {
	defer fmt.Println("in main")

	if err := recover(); err != nil {
		fmt.Println(err)
	}

	panic("unknow err")
}

运行结果

=== RUN   TestRecover
in main
--- FAIL: TestRecover (0.00s)
panic: unknow err [recovered]
	panic: unknow err

goroutine 6 [running]:
testing.tRunner.func1.1(0xddce00, 0xe30480)
	C:/Go/src/testing/testing.go:1072 +0x310
testing.tRunner.func1(0xc000027200)
	C:/Go/src/testing/testing.go:1075 +0x43a
panic(0xddce00, 0xe30480)
	C:/Go/src/runtime/panic.go:969 +0x1c7
GoProject/src/main/gobase/panic_recover.TestRecover(0xc000027200)
	D:/GoProject/src/main/gobase/panic_recover/panic_recover_test.go:38 +0x125
testing.tRunner(0xc000027200, 0xe10fc0)
	C:/Go/src/testing/testing.go:1123 +0xef
created by testing.(*T).Run
	C:/Go/src/testing/testing.go:1168 +0x2b3

在这里插入图片描述