2013-10-29 17 views
6

運行時間可以檢測到panic(nil)並報告錯誤。如何檢測延遲函數Go中的恐慌(無)和正常執行?

但是,我不能recover()defer紅色功能檢測panic(nil),因爲它返回nil,所以我不能正常執行(沒有出現恐慌)區別開來,因爲我會測試 的recover()返回值是零。

例如,

defer func(){ 
    var err = recover() 
    if err != nil { 
     // Real serious situation. Panic from inner code. 
     // And we may have some critical resources which 
     // must be cleaned-up at any cases. 
     // However, this will not be executed for panic(nil) 

     rollback() 

     // I am still not sure that how should I treat `panic`… 
     // Should I just ignore them? 
    } 
}() 

var err = doTransaction() 
if err == nil { 
    commit() // Happy case. 
} else { 
    rollback() // Regular execution. Just a lucky case. 
} 

ROLLBACK只是一個例子,我想我可以有很多危重病例需要清理。那麼,這些清理代碼也不會在真正的程序崩潰時執行,但我想盡可能地進行辯護。

無論延遲函數中的參數如何檢測到任何恐慌?

回答

4

除非我誤解了你的問題,否則即使通過的值是nil,延遲功能調用也會在恐慌時運行。這是由following program所示:

package main 

import "fmt" 

func main() { 
    defer func() { 
     fmt.Println("Recover:", recover()) 
    }() 
    panic(nil) 
} 

如果碰巧通過比較recover()回到nilpanic(nil)您可以輕鬆,因此檢測。

編輯回答評論:

是的,這是真的;延遲調用通常在函數返回時運行。但是當它們在panic()之後展開調用堆棧時,它們也會運行。問題後

編輯進行了更新:

你是正確的,有沒有辦法來區分這些情況。另一方面,與nil恐慌也沒有多大意義 - 特別是因爲這個限制。

我能想到的panic(nil)的唯一用例是故意避免恢復並強制程序崩潰並使用堆棧跟蹤。有更多優雅的方法可以做到這一點,例如使用runtime包。

+0

啊對不清楚的問題抱歉。我想要的是區分'panic(nil)'和'延遲'函數中的正常執行...... – Eonil

+0

也許我可以在退出函數之前設置一個標誌。 – Eonil

+0

感謝您的靈感!我通過設置標誌解決了這個問題。 – Eonil

2

我只是可以在退出之前設置一個標誌。

AFAIK,恐慌是goroutine特定的,單個goroutine保證是單線程。所以變量ok不需要同步/鎖定。如果我錯了,請糾正我。

func clean(ok *bool) { 
    if *ok { 
     log.Printf("Execution OK. No panic detected.\n") 
    } else { 
     var reason = recover() 
     log.Printf("Some bad thing happen. reason = %v\n", reason) 
     panic("Abnormal exit. Program abandoned. Stack-trace here.") 
     debug.PrintStack() // Oops. this will not run. 
    } 
} 

func main() { 
    var ok bool = false 

    defer clean(&ok) 
    panic(nil) 

    test1() // Here's the main job. 

    ok = true 
    log.Printf("All work done. Quit gracefully.\n") 
} 
+0

有一個標誌決定是否預期錯誤處理的最後手段** panic **的用途是什麼?你究竟在努力實現什麼?這在許多層面似乎都是錯誤的。 – nemo

+0

@nemo在我的情況下,如果任何'panic()'因任何原因發生,我需要在ROLLBACK中執行任何SQL命令。我認爲這是經典* try..catch..clean和rethrow *策略。因爲沒有關於某些功能的保證*內部沒有恐慌......任何更好的主意? – Eonil

+0

請使用這些信息更新您的問題,並解釋您爲什麼遇到無法解決的問題。 – nemo