9

go 运行时可以检测panic(nil)并报告错误。

但是,我无法在红色函数中检测到,因为它返回panic(nil),所以我无法将它与正常执行(没有恐慌)区分开来,因为我会测试返回值为nil。recover()defernilrecover()

例如,

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

2 回答 2

4

除非我误解了你的问题,否则延迟函数调用在恐慌时运行,即使传递的值是nil. 以下程序说明了这一点:

package main

import "fmt"

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

因此,您可以panic(nil)通过比较recover()to返回的值轻松检测是否发生nil

编辑以回答评论:

是的,这是真的; 当函数返回时,延迟调用通常会运行。但是在panic().

问题更新后编辑:

你是对的,没有办法区分这些情况。另一方面,恐慌nil也没有多大意义——尤其是因为这个限制。

panic(nil)我能想到的唯一用例是故意避免恢复并强制程序因堆栈跟踪而崩溃。不过,还有更优雅的方法可以做到这一点,runtime例如使用包。

于 2013-10-29T15:32:27.843 回答
4

我只需在退出前设置一个标志。

AFAIK,panic 是特定于 goroutine 的,并且单个 goroutine 保证在单线程中。因此 variable 不需要同步/锁定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")
}
于 2013-10-29T15:42:24.223 回答