Posted on 2013-09-22 09:32
oathleo 阅读(2231)
评论(0) 编辑 收藏 所属分类:
Golang
Panic和Recover
Go没有像Java那样的异常机制,它不能抛出异常,而是使用了panic
和recover
机制。一定要记住,你应当把它作为最后的手段来使用,也就是说,你的代码中应当没有,或者很少有panic
的东西。这是个强大的工具,请明智地使用它。那么,我们应该如何使用它呢?
Panic
是一个内建函数,可以中断原有的控制流程,进入一个令人恐慌的流程中。当函数F
调用panic
,函数F
的执行被中断,但是F
中的延迟函数会正常执行,然后F
返回到调用它的地方。在调用的地方,F
的行为就像调用了panic
。这一过程继续向上,直到发生panic
的goroutine
中所有调用的函数返回,此时程序退出。恐慌可以直接调用panic
产生。也可以由运行时错误产生,例如访问越界的数组。
Recover
是一个内建的函数,可以让进入令人恐慌的流程中的goroutine
恢复过来。recover
仅在延迟函数中有效。在正常的执行过程中,调用recover
会返回nil
,并且没有其它任何效果。如果当前的goroutine
陷入恐慌,调用recover
可以捕获到panic
的输入值,并且恢复正常的执行。
下面这个函数演示了如何在过程中使用panic
var user = os.Getenv("USER") func init() { if user == "" { panic("no value for $USER") } }
下面这个函数检查作为其参数的函数在执行时是否会产生panic
:
func throwsPanic(f func()) (b bool) { defer func() { if x := recover(); x != nil { b = true } }() f() //执行函数f,如果f中出现了panic,那么就可以恢复回来 return }
最容易理解就是给个例子,文章里有例子:
package main import( "fmt" //"os" ) var user = "" func inita() { defer func(){ fmt.Print("defer##\n") }() if user == "" { fmt.Print("@@@before panic\n") panic("no value for user\n") fmt.Print("!!after panic\n") } } func throwsPanic (f func()) (b bool){ defer func(){ if x:= recover(); x != nil{ fmt.Print(x) b = true } }() f() fmt.Print("after the func run") return } func main(){ throwsPanic(inita) }
执行结果:
D:\go>go run b.go
@@@before panic
defer##
no value for user
如上面所说的:
panic
在user=""
时,打断了函数的执行,fmt.Print("!!after panic\n")
没有执行。 但函数中的延迟函数会正常执行,打印了 defer##
。然后返回到调用该函数的地方,继续上面的过程。
直到执行完所有函数的defer
,退出程序。Recover
可以捕获到panic
的值,上面的打印no value for user
。并且恢复正常的执行。