error panic defer
python中可以用 try except来接收处理异常
go语言没有这些
go的错误分为两种,一种是人工手动抛出的错误error, 一种是程序执行出错的异常panic
defer
func DoDefer(){
fmt.Println("在defer之前执行")
defer fmt.Println("第一个defer")
defer func() {
fmt.Println("第二个defer")
}()
fmt.Println("我在defer中间,我也执行了")
defer fmt.Println("第三个defer")
fmt.Println("函数最后的语句执行了")
}
func main() {
DoDefer()
}
执行结果:
在defer之前执行
我在defer中间,我也执行了
函数最后的语句执行了
第三个defer
第二个defer
第一个defer
结论:
defer执行时间: 函数其他语句执行完之后
defer执行顺序: 堆栈顺序,从下往上
所以说函数中除defer语句之外的代码执行完之后,函数执行完毕,函数指令的堆栈触底上弹,此时开始从下往上执行注册的defer
defer翻译的意思是推迟,可以理解为是一个执行钩子,并且只在函数执行触底后出栈时才会执行(报错,panic也会导致函数提前出栈)
panic
panic是严重异常,如果不进行捕获的话,会导致程序退出
可以通过recover进行捕获,需要配合defer关键字
func panicErr(info string) {
panic("Panic Error " + info)
}
func MustError() {
defer func() {
err := recover()
fmt.Println("Yes, Cover error", err)
}()
fmt.Println("异常之前,即将触发异常")
panicErr("After")
fmt.Println("异常之后,异常函数内的代码仍然执行了")
}
func main() {
MustError()
fmt.Println("异常发生后,异常函数之外的代码仍然执行了")
}
执行结果:
异常之前,即将触发异常
Yes, Cover error Panic Error After
异常发生后,异常函数之外的代码仍然执行了
可以看到,在执行出错的函数之前通过defer注册出栈的函数,当注册之后的函数抛出panic后,会进行正常捕获,捕获的函数MustError内,代码执行按照通常异常处理的方式中断,并且出栈,该函数出错语句之后的代码不再执行
函数的调用者函数依然可以正常执行
这和try except / try catch不通,try语法处理完try代码块内的代码,不影响函数try外的代码执行
但是defer recover 不行,只要报错,整个函数立即终止
再看另个形式:
func panicErr(info string) {
panic("Panic Error " + info)
}
func MustError() {
panicErr("Before")
defer func() {
err := recover()
fmt.Println("Yes, Cover error", err)
}()
fmt.Println("异常之前,即将触发异常")
panicErr("After")
fmt.Println("异常之后,异常函数内的代码仍然执行了")
}
func main() {
MustError()
fmt.Println("异常发生后,异常函数之外的代码仍然执行了")
}
和上面不同的是,在defer注册出栈函数之前,先执行了一次抛出错误的函数,结果就是defer语句无效了
因为代码入栈仍然是从上往下,还没到注册defer,就已经报错了,所以出栈的时候defer的recover还没注册,自然执行不到了
所以,defer语句,最好在函数最开始就定义!!!
error
error在go里面是error接口的实例,不是异常,更像是一个专用于错误信息的类
函数通过return的方式来抛出异常,不会像panic或者Python Exception 那样不断往上抛出直到被捕获,如果不接收,代码编译会出错,如果不想处理,可以用 _
来接收,接收后不进行处理也不会出错, 但是可能会造成编程人员对程序运行的期望出现偏差。
error更像是一种报警信息,告诉程序员函数调用出现了意料之外的情况,需要注意,或者做相应处理
error不像panic那样强制性的必须处理。