Posted on 2013-09-22 09:32
oathleo 閱讀(2235)
評(píng)論(0) 編輯 收藏 所屬分類:
Golang
Panic和Recover
Go沒有像Java那樣的異常機(jī)制,它不能拋出異常,而是使用了panic
和recover
機(jī)制。一定要記住,你應(yīng)當(dāng)把它作為最后的手段來使用,也就是說,你的代碼中應(yīng)當(dāng)沒有,或者很少有panic
的東西。這是個(gè)強(qiáng)大的工具,請(qǐng)明智地使用它。那么,我們應(yīng)該如何使用它呢?
Panic
是一個(gè)內(nèi)建函數(shù),可以中斷原有的控制流程,進(jìn)入一個(gè)令人恐慌的流程中。當(dāng)函數(shù)F
調(diào)用panic
,函數(shù)F
的執(zhí)行被中斷,但是F
中的延遲函數(shù)會(huì)正常執(zhí)行,然后F
返回到調(diào)用它的地方。在調(diào)用的地方,F
的行為就像調(diào)用了panic
。這一過程繼續(xù)向上,直到發(fā)生panic
的goroutine
中所有調(diào)用的函數(shù)返回,此時(shí)程序退出。恐慌可以直接調(diào)用panic
產(chǎn)生。也可以由運(yùn)行時(shí)錯(cuò)誤產(chǎn)生,例如訪問越界的數(shù)組。
Recover
是一個(gè)內(nèi)建的函數(shù),可以讓進(jìn)入令人恐慌的流程中的goroutine
恢復(fù)過來。recover
僅在延遲函數(shù)中有效。在正常的執(zhí)行過程中,調(diào)用recover
會(huì)返回nil
,并且沒有其它任何效果。如果當(dāng)前的goroutine
陷入恐慌,調(diào)用recover
可以捕獲到panic
的輸入值,并且恢復(fù)正常的執(zhí)行。
下面這個(gè)函數(shù)演示了如何在過程中使用panic
var user = os.Getenv("USER") func init() { if user == "" { panic("no value for $USER") } }
下面這個(gè)函數(shù)檢查作為其參數(shù)的函數(shù)在執(zhí)行時(shí)是否會(huì)產(chǎn)生panic
:
func throwsPanic(f func()) (b bool) { defer func() { if x := recover(); x != nil { b = true } }() f() //執(zhí)行函數(shù)f,如果f中出現(xiàn)了panic,那么就可以恢復(fù)回來 return }
最容易理解就是給個(gè)例子,文章里有例子:
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) }
執(zhí)行結(jié)果:
D:\go>go run b.go
@@@before panic
defer##
no value for user
如上面所說的:
panic
在user=""
時(shí),打斷了函數(shù)的執(zhí)行,fmt.Print("!!after panic\n")
沒有執(zhí)行。 但函數(shù)中的延遲函數(shù)會(huì)正常執(zhí)行,打印了 defer##
。然后返回到調(diào)用該函數(shù)的地方,繼續(xù)上面的過程。
直到執(zhí)行完所有函數(shù)的defer
,退出程序。Recover
可以捕獲到panic
的值,上面的打印no value for user
。并且恢復(fù)正常的執(zhí)行。