Golang的panic和recover


panic

  關鍵字panic的作用是制造一次宕機,宕機就代表程序運行終止,但是已經“生效”的延遲函數仍會執行(即已經壓入棧的defer延遲函數,panic之前的)。

  為什么要制造宕機呢?是因為宕機不容易遇到?還是因為程序有錯就是直接報錯,都沒有執行,哪來的宕機?

  Go程序設計語言中這樣提到:如果碰到“不可能發生的”的狀況,宕機是最好的處理方式。這個“不可能發生的”狀況很難理解,不過可以這樣想:一個機器人的能源供應,可能依靠太陽能,可能依靠電能,但是如果靠吃飯解決,那么這肯定就不可思議了,這時候就應該觸發一次宕機。

關於panic,下面是一個例子:

package main
import "fmt"
func main(){
    defer func(){
        fmt.Println("aaaaaa")
    }()
    fmt.Println("bbbbbb")
    fmt.Println("cccccc")
    panic("hahahaha")
    fmt.Println("ddddd")
    defer func(){
        fmt.Println("eeeeeeee")
    }()
}

  首先順序執行,會先將第一個defer延遲函數“入棧”(這里稱為入棧是為了便於理解),然后輸出“bbbbbbb",”cccccccc”,此時使用panic來觸發一次宕機,panic接受一個任意類型的參數,會將該字符串輸出,用作提示信息,之后的代碼不再執行,所以后面的dddddd不會輸出,而且第二個defer延遲函數也不會“入棧”,因為panic之后的代碼不會繼續執行,程序現在只會運行已經“入棧”的defer延遲函數,輸出aaaaaa,在最后,會輸出此次觸發宕機的一些信息,所以執行結果如下:

bbbbbb
cccccc
aaaaaa
panic: hahahaha

goroutine 1 [running]:
main.main()
	/Users/root/Desktop/test.go:9 +0xf1
exit status 2

  為什么不執行panic后面的defer,其實這個很好理解,比如,有兩次讀文件操作,那么每一次讀文件之后都是用defer關閉文件,如果第一次讀文件就引發了panic異常,而第二次讀文件操作還沒開始,也就是說還沒有打開文件,那么調用第二個defer來關閉第二個文件,有意義嗎?應該是只關閉第一個打開的文件,對吧?也就是調用第一個defer。

recover

   recover從英文的意思上就知道是恢復,那么這個恢復是恢復什么呢?是恢復運行狀態,繼續運行?還是恢復到宕機之前?

  其實,recover在英文中指的是受傷的愈合,防止傷口進一步感染。傷是愈合了,但是傷了始終是傷了,愈合只不過是事后處理而已。所以golang中的recover也只是發生宕機之后的后事處理。

  所以這里的recover只是用來接收panic觸發的宕機,如果panic觸發宕機,傳給panic的任意類型的參數,recover會接收到這個參數,recover獲取到值之后才知道發生了宕機;相反,如果程序中的recover沒有獲取到值,則代表沒有發生宕機,那么recover的值就為nil,通過這個可以來進一步處理后事。

  前面已經提到panic的時候,已經說了,一旦發生宕機,其后的代碼是不會執行的,但是會調用位於panic代碼所在的哪一行之前的defer延遲函數,所以說這個特性就決定recover應該用在defer函數中,否則一旦發生宕機,除了defer延遲函數中的語句還能執行外,其他的語句都是不能執行的。

  如果觸發宕機,panic的錯誤信息會顯示,如果有recover時,則信息會被recover截獲,於是錯誤信息就不會顯示,轉而進行下一步操作。

下面是一個簡單的示例:

package main
import "fmt"
func main() {
	defer func() {
		if info := recover(); info != nil {
			fmt.Println("觸發了宕機", info)
		} else {
			fmt.Println("程序正常退出")
		}
	}()
	fmt.Println("bbbbbb")
	fmt.Println("cccccc")
	panic("fatal error")
	fmt.Println("ddddd")
	defer func() {
		fmt.Println("eeeeeeee")
	}()
}

  運行結果如下:

bbbbbb
cccccc
觸發了宕機 fatal error

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM