Go 中的Panic和Recover

GO没有像Java那样的异常机制,不能抛出异常而是使用了panicrecover机制。

一定要记住,你应当把它作为最后的手段来使用,也就是说,你的代码中应当没有,或者很少有panic的东西。这是个强大的工具,请明智地使用它。那么,我们应该如何使用它呢?

使用panic抛出异常,抛出异常后将立即停止当前函数的执行并运行所有被defer的函数,然后将panic抛向上一层,直至程序carsh。但是也可以使用被defer的recover函数来捕获异常阻止程序的崩溃,recover只有被defer后才是有意义的

注意点:

  1. defer 需要放在 panic 之前定义,另外recover只有在 defer 调用的函数中才有效。
  2. recover处理异常后,逻辑并不会恢复到 panic 那个点去,函数跑到 defer 之后的那个点.
  3. 多个 defer 会形成 defer 栈,后定义的 defer 语句会被最先调用
  • panic (主动爆出异常) 与 recover (收集异常)
  • recover 用来对panic的异常进行捕获. panic 用于向上传递异常,执行顺序是在 defer 之后。

Panic

是一个内建函数,可以中断原有的控制流程,进入一个令人恐慌的流程中。当函数F调用panic,函数F的执行呗中断,但是F中的延迟函数会正常执行,然后F返回到调用它的地方,F的行为就像调用了panic。直到发生panic的goroutine中所有调用的函数返回,此时程序退出。恐慌可以直接调用panic产生。也可以由运行时错误产生,例如访问越界的数组。

Recover

是一个内建的函数,可以让进入令人恐慌的流程中的goroutine恢复过来。recover仅在延迟函数中有效。在正常的执行过程中,调用recover会返回nil,并且没有其它任何效果。如果当前的goroutine陷入恐慌,调用recover可以捕获到panic的输入值,并且恢复正常的执行。

下面这个函数演示了如何在过程中使用panic

package main

import (
	"fmt"
	"time"
)

func main() {
	for {
		fmt.Println("1")
		a := []string{"a", "b"}
		fmt.Println(a[3]) // 这里slice越界异常了
		/*panic("bug")*/
		fmt.Println("4")
		time.Sleep(1 * time.Second)
	}
}

此时会抛出异常

1
panic: runtime error: index out of range

goroutine 1 [running]:
main.main()
	/Users/lit_leaf/Desktop/go学习/day01/15.defer.go:12 +0x7b

Process finished with exit code 2	

下面是处理panic的例子

package main
 
import (
    "fmt"
    "time"
)
 
func main() {
    defer func() { //必须要先声明defer,否则不能捕获到panic异常
        fmt.Println("2")
        if err := recover(); err != nil {
            fmt.Println(err) //这里的err其实就是panic传入的内容,bug
        }
        fmt.Println("3")
    }()
    f()
}
 
func f() {
    for {
        fmt.Println("1")
        panic("bug")
        fmt.Println("4") //不会运行的.
        time.Sleep(1 * time.Second)
    }

上面的代码运行结果是

1
2
bug
4

上面go代码实例中,异常使我们用过panic方法主动抛出来的,但是如果真的遇到了未知的异常怎么办?

package main

import (
	"fmt"
	"time"
)


func main() {
	f()
	fmt.Println("end")
}

func f() {
	defer func() { //必须要先声明defer,否则不能捕获到panic异常
		fmt.Println("start")
		if err := recover(); err != nil {
			fmt.Println(err) //这里的err其实就是panic传入的内容,"bug"
		}
		fmt.Println(" end")
	}()
	for {
		fmt.Println("1")
		a := []string{"a", "b"}
		fmt.Println(a[3])  // 越界访问,肯定出现异常
		panic("bug")  // 上面已经出现异常了,所以肯定走不到这里了。
		fmt.Println("4") //不会运行的.
		time.Sleep(1 * time.Second)
	}
}

运行结果

1
start
runtime error: index out of range
 end
end

我们可以看到出现的异常会走到defer这一步,defer这里可以打印具体的异常信息,defer运行完之后不能回到原点,控制权会被扔到该函数的外层,也就是调用这个函数的层,对应上面的代码也就是main()函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值