3 回答

TA貢獻1829條經驗 獲得超9個贊
引用內置函數的文檔recover():
如果在延遲函數之外調用恢復,它不會停止恐慌序列。
在您的第二種情況下,recover()它本身就是延遲函數,顯然 recover()不會調用自己。所以這不會停止恐慌序列。
如果它自己recover()調用recover(),它會停止恐慌序列(但為什么會這樣做?)。
另一個有趣的例子:
下面的代碼也不會驚慌(在Go Playground上試試):
package main
func main() {
var recover = func() { recover() }
defer recover()
panic("panic")
}
這里發生的事情是我們創建了一個recover函數類型的變量,它具有調用內置函數的匿名函數的值recover()。并且我們指定調用recover變量的值作為延遲函數,因此recover()從中調用內置函數會停止恐慌序列。

TA貢獻1862條經驗 獲得超7個贊
該處理恐慌部分提到,
兩個內置函數
panic
和recover
,幫助報告和處理運行時恐慌該
recover
函數允許程序管理恐慌 goroutine 的行為。假設一個函數
G
延遲了一個D
調用的函數,recover
并且 apanic
出現在G
正在執行的同一個 goroutine 上的函數中。當延遲函數的運行達到 時
D
,D
的調用返回值recover
將是傳遞給恐慌調用的值。
如果 D 正常返回,沒有開始新的恐慌,恐慌序列就會停止。
這說明這recover
意味著在延遲函數中調用,而不是直接調用。
當它恐慌時,“延遲函數”不能是內置函數recover()
,而是在defer 語句中指定的函數。
DeferStmt = "defer" Expression .
表達式必須是函數或方法調用;不能用括號括起來。
內置函數的調用與表達式語句一樣受到限制。除了特定的內置函數,函數和方法調用和接收操作都可以出現在語句上下文中。

TA貢獻2051條經驗 獲得超10個贊
一個觀察是,這里真正的問題是設計,defer因此答案應該是這樣的。
激發這個答案,defer目前需要從 lambda 中獲取一級嵌套堆棧,并且運行時使用此約束的特定副作用來確定是否recover()返回 nil。
這是一個例子:
func b() {
defer func() { if recover() != nil { fmt.Printf("bad") } }()
}
func a() {
defer func() {
b()
if recover() != nil {
fmt.Printf("good")
}
}()
panic("error")
}
將recover()在b()應返回零。
在我看來,更好的選擇是將defer函數 BODY 或塊作用域(而不是函數調用)作為參數。在這一點上,panic和所述recover()返回值可以被綁定到特定堆棧幀,任何內堆棧幀將具有nilpancing上下文。因此,它看起來像這樣:
func b() {
defer { if recover() != nil { fmt.Printf("bad") } }
}
func a() {
defer {
b()
if recover() != nil {
fmt.Printf("good")
}
}
panic("error")
}
在這一點上,很明顯它a()處于恐慌狀態,但b()不是,并且不需要任何副作用,例如“位于延遲 lambda 的第一個堆棧幀中”,以正確實現運行時。
因此,這里有悖常理:之所以沒有按預期工作,是defer因為 go 語言中關鍵字的設計存在錯誤,這是使用不明顯的實現細節副作用解決的,然后編碼為這樣的。
- 3 回答
- 0 關注
- 401 瀏覽
添加回答
舉報