我注意到panic
需要interface{}
作爲參數,而fmt.Print
等喜歡採用...interface{}
。如果panic
還需要...interface{}
,不是更方便嗎?爲什麼Go panic()將interface {}而不是... interface {}作爲參數?
爲什麼Go作者將panic
定義爲func panic(v interface{})
而不是func panic(v ...interface{})
(就像他們使用fmt
一樣)?
我注意到panic
需要interface{}
作爲參數,而fmt.Print
等喜歡採用...interface{}
。如果panic
還需要...interface{}
,不是更方便嗎?爲什麼Go panic()將interface {}而不是... interface {}作爲參數?
爲什麼Go作者將panic
定義爲func panic(v interface{})
而不是func panic(v ...interface{})
(就像他們使用fmt
一樣)?
panic
沒有采取只有一個參數在第一。
可以追溯一個參數實現回至2010年3月30日:
commit 01eaf78 GC:添加panic
和recover
(還沒有實現在運行時)
主要語義變化是執行單一參數恐慌。
該規範是固定的commit 5bb29fb和commit 00f9f0c說明恐慌可能同時有多個參數之前花:
src/pkg/bufio/bufio.go
b, err := NewWriterSize(wr, defaultBufSize)
if err != nil {
// cannot happen - defaultBufSize is valid size
- panic("bufio: NewWriter: ", err.String())
+ panic(err)
}
這是繼一proposal from March 25th, 2010:
我們不希望以鼓勵在諸如Java等語言中出現的錯誤和異常的混合。
相反,本提案對延遲的定義和一些運行時函數稍作修改,以提供一種乾淨的機制來處理真正的異常情況。
在恐慌期間,如果延遲函數調用調用recover,recover將返回傳遞給panic的值並停止恐慌。
在任何其他時間或在延期調用調用的函數內,恢復返回nil。
停止恐慌後,延遲呼叫可能會出現新的參數或同一個參數,以繼續恐慌。
或者,延遲調用可能會編輯其外部函數的返回值,可能會返回錯誤。
在這些不同的情況下,處理一個值來繞過似乎比處理的參數(尤其是當它涉及到implement recover
in C)的可變數目更容易。
此外,如果恐慌是可變的,爲了像'errors.New(fmt.Sprint(... args))這樣的方便',它會鼓勵使用恐慌,實際上,當恐慌用作控制流機制時是不鼓勵的,並且應該很少,如果有的話,通過包裝邊界。發生這種恐慌時,應在每個功能的包裝文檔中明確記錄它們。 – krait
因爲您傳遞給panic
的值是您想要驚嚇的值,可以使用recover
來檢索。有多個恐慌值並不合理。使用恢復值
package main
import "fmt"
func main() {
defer func() {
if v := recover(); v != nil {
fmt.Println(v.(int))
}
}()
panic(3)
}
實施例:
對於恐慌的真實世界實施例和恢復,從轉到標準庫看到JSON包 。它使用遞歸函數的集合 解碼JSON編碼的數據。遇到格式錯誤的JSON時,解析器 調用panic將堆棧展開到頂層函數調用,該函數調用將從panic中恢復並返回相應的錯誤值(請參閱 decodeState的'error'和'unmarshal'方法輸入 decode.go)。
但是,除非是非常特殊的情況,否則你絕不應該使用恐慌,對吧?所以如果我需要處理一個錯誤,我只是處理'err'。如果我的程序發生混亂,我只想讓它崩潰,或者將它打印到某些日誌中。如果採用可變參數,您仍然可以只查看片中的第一個項目,並且可以輕鬆地覆蓋您的用例。傳遞一個錯誤代碼和導致它的結構看起來像是很好的使用了多個參數。 –
@FilipHaglund我用一個例子更新了答案,如何在內部使用恐慌進行json解碼。 – Arjan
是的,我讀過。這只是一種用途,但這不是恐慌的普遍用法,還是它?展開堆棧可以很快完成,如果錯誤!= nil',對吧? –
致主持人錯誤地投票結束這個問題:這與「基於意見」無關:這是一個非常重要的問題,要求解決基礎語言設計問題的根源。閱讀我的答案:這裏沒有意見。 – VonC