在上一節,咱們已經瞭解到了足夠多的error
接口及其周邊的知識。如今,是學習另一種異常處理方式的時候了。先來展現一個名詞——panic
。panic
可被意譯爲運行時恐慌。由於它只有在程序運行的時候纔會被「拋出來」。而且,恐慌是會被擴散的。當有運行時恐慌發生時,它會被迅速地向調用棧的上層傳遞。若是咱們不顯式地處理它的話,程序的運行瞬間就會被終止。這裏有一個專有名詞——程序崩潰。內建函數panic
可讓咱們人爲地產生一個運行時恐慌。不過,這種致命錯誤是能夠被恢復的。在Go語言中,內建函數recover
就能夠作到這一點。
實際上,內建函數panic
和recover
是天生的一對。前者用於產生運行時恐慌,然後者用於「恢復」它。不過要注意,recover
函數必需要在defer
語句中調用纔有效。由於一旦有運行時恐慌發生,當前函數以及在調用棧上的全部代碼都是失去對流程的控制權。只有defer
語句攜帶的函數中的代碼纔可能在運行時恐慌迅速向調用棧上層蔓延時「攔截到」它。這裏有一個能夠起到此做用的defer
語句的示例:函數
defer func() { if p := recover(); p != nil { fmt.Printf("Fatal error: %s\n", p) } }()
在這條defer
語句中,咱們調用了recover
函數。該函數會返回一個interface{}
類型的值。還記得嗎?interface{}
表明空接口。Go語言中的任何類型都是它的實現類型。咱們把這個值賦給了變量p
。若是p
不爲nil
,那麼就說明當前確有運行時恐慌發生。這時咱們需根據狀況作相應處理。注意,一旦defer
語句中的recover
函數調用被執行了,運行時恐慌就會被恢復,不論咱們是否進行了後續處理。因此,咱們必定不要只「攔截」不處理。
咱們下面來反觀panic
函數。該函數可接受一個interface{}
類型的值做爲其參數。也就是說,咱們能夠在調用panic
函數的時候能夠傳入任何類型的值。不過,我建議你們在這裏只傳入error
類型的值。這樣它表達的語義纔是精確的。更重要的是,當咱們調用recover
函數來「恢復」因爲調用panic
函數而引起的運行時恐慌的時候,獲得的值正是調用後者時傳給它的那個參數。所以,有這樣一個約定是頗有必要的。
總之,運行時恐慌表明程序運行過程當中的致命錯誤。咱們只應該在必要的時候引起它。人爲引起運行時恐慌的方式是調用panic
函數。recover
函數是咱們常會用到的。由於在一般狀況下,咱們確定不想由於運行時恐慌的意外發生而使程序崩潰。最後,在「恢復」運行時恐慌的時候,你們必定要注意處理措施的得當。學習