Go每天一篇(day64)----panic()和recover()

一、今日題目
  1. 下面列舉的是recover()的幾種調用方式,哪些是正確的?
    A.

    func A() {
    	recover()
    	panic(1)
    }
    

    B.

    func main() {
    	defer recover()
    	panic(1)
    }
    

    C.

    func main() {
    	defer func() {
    		recover()
    	}()
    	panic(1)
    }
    

    D.

    func main() {
    	defer func() {
    		defer func() {
    			recover()
    		}()
    	}()
    	panic(1)
    }
    
  2. 下面代碼會輸出什麼,請說明?

    func main() {
    	defer func() {
    		fmt.Print(recover())
    	}()
    	defer func() {
    		defer fmt.Print(recover())
    		panic(1)
    	}()
    	defer recover()
    	panic(2)
    }
    
二、答案:
  1. C
  2. 21
三、解析:
  1. recover() 必須在defer函數中直接調用纔有效。A、B和D這幾種情況的調用都是無效的:直接調用recover()、在defer()中直接調用recover()和defer()調用時多層嵌套。
  2. recover() 必須在defer()函數中調用纔有效,所以第9行代碼捕獲是無效的。在調用defer()時,便會計算函數的參數並壓入棧中,defer()的執行順序爲:先進後出。最後panic(2)會向上傳遞到第二個defer()中。所以在執行第6行代碼時,會捕獲panic(2);此後的panic(1),繼續向上傳遞會被上一層的recover()捕獲。
四、相關知識總結:
1. panic()函數

panic是用來表示非常嚴重的且不可恢復的錯誤的。在Go語言中這是個內置函數,接受一個interface{}類型的值(也就是任何值)作爲參數。panic的作用就是異常,不過Go中沒有try…catch,所以panic一般會導致程序掛掉(除非有recover)。
注意:即使函數執行的時候panic了,函數不往下走了,運行時並不是立刻向上傳遞panic,而是到defer那,等defer的東西都跑完了,panic再往上傳遞。

2.recover()函數

Go語言提供recover內置函數,用來捕獲拋出的異常panic。
需要注意的是:必須要先聲明defer,否則不能捕獲到panic異常。正如上面說到的 ,recover()必須再defer函數中直接調用纔有效。不使用defer,直接defer recover(),或者嵌套使用defer 函數調用都是無效的。
recover()捕獲異常的機制:一旦遇到panic,panic函數不會立刻就返回,而是邏輯走到defer那,然後我們就在defer這調用recover函數就會捕獲當前的panic(如果有的話),然後將defer執行完。但是recover之後邏輯不會再恢復到panic那個點去。函數會在defer之後返回。這時捕獲的panic就不會向上傳遞了,程序就可以正常運行了。

實例:
func main() {
	defer func() {
		fmt.Println("c")
		fmt.Println(recover())
		fmt.Println("d")
	}()
	f()
}
func f()  {
	fmt.Println("a")
	panic(55)
	fmt.Println("b")
	fmt.Println("f")
}

輸出結果:
a
c
55
d

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章