go的错误处理机制

defer

  • go语言是实用defer做资源处理的
  • defer是在函数结束,return之前时被调用
  • 先进后出,可见是栈的结构
  • 参数在defer语句时计算

何时使用defer
  • open/close
  • lock/unlock
  • printHeader/printFooter

func calc(index string, a, b int) int {
	ret := a + b
	fmt.Printf("%s %d + %d = %d\n",index, a, b, ret)
	return ret
}


func main() {
	a := 1
	b := 2
	defer calc("first  defer:", a, calc("first  inner:", a, b))
	a = 3
	defer calc("second defer:", a, calc("second inner:", a, b))
	b = 4
}


//结果
//first  inner: 1 + 2 = 3
//second inner: 3 + 2 = 5
//second defer: 3 + 5 = 8
//first  defer: 1 + 3 = 4

  • 根据defer的执行顺序, first defer肯定是最后执行的
  • first defer虽然最后执行,但是其参数first inner却是第一个执行
  • first defer执行时的参数状态,保留的是其位置之前的,比如a后来修改成了3对其没有任何影响


panit/recover

 
panic

  • 停止当前函数执行
  • 一直向上返回,执行每一层的defer
  • 如果没有遇见recover,程序退出

recover
  • 仅在defer调用中使用,程序运行中间是没法调用recover的
  • defer的时候,获取panic的值
  • 如果无法处理,可重新panic

func tryRecover(){
	defer func() {
		r := recover()
		// r是一个interface接口类型
		if err, ok := r.(error); ok{
			fmt.Println("error occurred", err)
		} else{
			panic(r)
		}
	}()
	panic(errors.New("this is a error"))  
	panic("this is a error")
}


func main(){
	tryRecover()
}
  • 如果是第一句panic ,那参数是error类型,recover获得的也是error类型,则打印出结果为: error occurred : this is a error
  • 如果是第二句panic,那recover获得的就是string类型,打印出来就是栈的异常信息
  • 但是如果把err, ok := r.(error)改为err, ok := r.(string),则正常打印 error occurred : this is a error

实例:

func tryRecover(){
	fmt.Println("tryRecover 1...")
	defer func() {
		r := recover()
		if err, ok := r.(error); ok{
			fmt.Println("error occurred: ", err)
		} else{
			panic(r)
		}
	}()
	cala()
	fmt.Println("tryRecover 3...")
}


func cala(){
	fmt.Println("cala 1...")
	b := 0
	a := 1/b
	fmt.Println(a)
	fmt.Println("cala 2...")
}


func main(){
	fmt.Println("start ...")
	tryRecover()
	fmt.Println("end ...")
}

输出结果:

start ...
tryRecover 1...
error occurred:  runtime error: integer divide by zero
end ...

  • 如果一个方法有异常(不管是来自于自己还是来自于调用方法),而且这个方法里没有recover的话,他会直接退出的,并且讲错误信息返回给上一层的。
  • 如果一个方法有异常(不管是来自于自己还是来自于调用方法),且有recover,那么异常语句其后面的代码都不会执行了,直接进入recover,如果recover不再次panic,上一层正常执行下去

比如:

func tryRecover(){
	fmt.Println("tryRecover 1...")
	cala()
	fmt.Println("tryRecover 3...")
}


func cala(){
	fmt.Println("cala 1...")
	defer func() {
		r := recover()
		if err, ok := r.(error); ok{
			fmt.Println("error occurred: ", err)
		} else{
			panic(r)
		}
	}()
	b := 0
	a := 1/b
	fmt.Println(a)
	fmt.Println("cala 2...")
}


func main(){
	fmt.Println("start ...")
	tryRecover()
	fmt.Println("end ...")
}

结果是:

start ...
tryRecover 1...
cala 1...
error occurred:  runtime error: integer divide by zero
tryRecover 3...
end ...


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值