panic和recover的使用規則

2021-09-11 08:50:26 字數 2639 閱讀 5995

**:

**個人部落格 chinazt.cc

在上一節中,我們介紹了defer的使用。 這一節中,我們溫習一下panic和recover的使用規則。

在golang當中不存在tye ... catch 異常處理邏輯。在golang當中使用defer, panic和recover來控制程式執行流程,藉此來達到處理異常的目的。

panic是乙個可以停止程式執行流程的內建函式。 假設當前f函式當中某處**觸發panic函式,則f函式停止後面**的執行,轉而執行f函式內部的defer函式(如果已經宣告了defer函式的話...),然後結束f函式,將當前處理權轉給f的呼叫函式。

對於f的呼叫方m來說,f是呼叫panic函式結束的,而不是執行return結束的。這一點很重要,因為呼叫panic函式結束是沒有返回值的。

對於f的呼叫方m來說,f呼叫結束並且已經退出。所以引出第乙個規則:

我們通過下面的**來解釋這個問題:

package main

import "fmt"

func main()

func f()

}()fmt.println("calling g.")

g(0)

fmt.println("returned normally from g.")

}func g(i int)

defer fmt.println("defer in g", i)

fmt.println("printing in g", i)

g(i + 1)

}

這段函式裡面,當i大於3之後,觸發panic函式。 在i小於3之前,一切正常。 引出我們來分析一下執行邏輯。

當i==4時,開始觸發panic函式,輸出panicking!。需要記住panic之後,呼叫方直接從呼叫點退出。 因為g()裡面是迭代呼叫,因此當i==4時觸發panic時,本質是g(i+1)這一行觸發的panic函式。 因此g()後續的函式不再繼續執行,因為存在defer函式了,所以連續輸出三個"defer in g"。

此時g(0)函式執行完畢,f()函式退出。因為f()函式裡面存在defer函式,因此會呼叫defer 輸出"recoverd in f"。

所以最終的輸出結果將是:

calling g.

printing in g 0

printing in g 1

printing in g 2

printing in g 3

panicking!

defer in g 3

defer in g 2

defer in g 1

defer in g 0

recovered in f 4

returned normally from f.

聊完執行順序的問題後,我們來看為什麼會輸出"recovered in f 4". 這就是規則二:

panic存在的意義,不僅可以控制異常處理流程,還可以用來返回異常原因。如果panic不給呼叫方返回異常原因,那麼呼叫方就無從下手處理問題。 因此在呼叫panic時,一般來說都是返回乙個字串,用來標示失敗原因。例如上面**中的"***值不得大於3"。

panic的返回值,通過recover函式來獲取。 recover函式也是乙個內建函式,專門用來接收panic函式返回值。當panic函式沒有被呼叫或者沒有返回值時,recover返回nil.

在使用recover函式時,就需要下面的規則三:

注意此處的有效果不等於執行。言外之意,recover函式可以在任何地方執行,但只有在defer**塊中執行才能真正達到處理異常的目的。

我們假設,將recover函式移除defer**塊,如下:

func f() int 

fmt.println("returned normally from g.", m)

return m

}

因為recover函式在外,因此執行結果如下:

calling g.

printing in g 0

printing in g 1

printing in g 2

printing in g 3

panicking!

defer in g 3

defer in g 2

defer in g 1

defer in g 0

panic: 4

goroutine 1 [running]:

[stack trace omitted]

可以看到recover函式並未生效,其實是沒有執行,因為根據規則一,當前執行流程會跳轉到defer函式中。因此只有將recover函式定義到defer之中才會真正被執行。

那麼問題來了,recover函式應該定義在哪一級的defer中。 golang是逐級查詢的,最終會查詢到main函式。 如果main函式中的defer還沒有recover函式,golang這會像上面那樣丟擲最終的異常資訊。

本節內容不多,但個人感覺還都是乾貨。 畢竟我們不能保證自己的寫的**一定就沒有問題,有問題不可怕,可怕的是**不受控制。所以學好defer,panci和recover,有助於寫出健壯的**。

Go 筆記 關於 Panic和 Recover

今天看了一下go語言,在講到以往其他語言的異常的時候,go採用了不同的方式 panic 函式類似於丟擲乙個異常,這個異常會中斷當前的執行函式 在 defer 的延遲執行環境中,呼叫 recover 如果 recover 返回的是 nil表示正常執行,如果非 nil 表示這個 defer延遲環境中 捕...

recover和restore的區別

recover和restore的區別 restore just copy the physical file,recover will consistent the database.restore 是還原,檔案級的恢復。就是物理檔案還原。recover 是恢復,資料級的恢復。邏輯上恢復,比如應用歸...

golang中defer和recover函式

defer語句是用來延遲執行 的,意思就是在執行一段 的時候,只有執行完畢那一時間,才會執行defer語句。而且在遇見多個defer的時候,最開始的defer會是最後乙個執行,可以通過以下 看出來 package main import fmt func main defer fmt.println...