亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

為什么`defer recovery()` 沒有捕捉到恐慌?

為什么`defer recovery()` 沒有捕捉到恐慌?

Go
嚕嚕噠 2021-09-27 17:45:31
為什么調用defer func() { recover() }()成功恢復恐慌的 goroutine,但調用不成功defer recover()?作為一個簡約的例子,這段代碼不會恐慌package mainfunc main() {    defer func() { recover() }()    panic("panic")}然而,用recover直接替換匿名函數會導致恐慌package mainfunc main() {    defer recover()    panic("panic")}
查看完整描述

3 回答

?
PIPIONE

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()從中調用內置函數會停止恐慌序列。


查看完整回答
反對 回復 2021-09-27
?
牧羊人nacy

TA貢獻1862條經驗 獲得超7個贊

處理恐慌部分提到,

兩個內置函數panicrecover,幫助報告和處理運行時恐慌

recover函數允許程序管理恐慌 goroutine 的行為。

假設一個函數G 延遲了一個D調用的函數,recover并且 apanic出現在G正在執行的同一個 goroutine 上的函數中。

當延遲函數的運行達到 時D,D的調用返回值recover將是傳遞給恐慌調用的值。
如果 D 正常返回,沒有開始新的恐慌,恐慌序列就會停止。

這說明這recover意味著在延遲函數中調用,而不是直接調用。
當它恐慌時,“延遲函數”不能是內置函數recover(),而是在defer 語句中指定的函數。

DeferStmt = "defer" Expression .

表達式必須是函數或方法調用;不能用括號括起來。
內置函數的調用與表達式語句一樣受到限制。

除了特定的內置函數,函數和方法調用和接收操作都可以出現在語句上下文中。


查看完整回答
反對 回復 2021-09-27
?
侃侃無極

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 語言中關鍵字的設計存在錯誤,這是使用不明顯的實現細節副作用解決的,然后編碼為這樣的。


查看完整回答
反對 回復 2021-09-27
  • 3 回答
  • 0 關注
  • 401 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號