【问题标题】:Golang Defer a closureGolang 推迟关闭
【发布时间】:2020-06-22 02:24:46
【问题描述】:

我是新手,学习推迟。我想知道为什么第一个有效而第二个无效。我想知道它们之间有什么区别。 第一:

func say(s string) {
    defer func() {
        if  r := recover(); r != nil {
            fmt.Println("Recovered in cleanup:", r)
        }
        wg.Done()
    }()
    for i := 0; i < 3; i++ {
        fmt.Println(s)
        time.Sleep(time.Millisecond * 100)
        if i == 2 {
            panic("oh")
        }
    }
}

第二:

func cleanup(){
        if  r := recover(); r != nil {
            fmt.Println("Recovered in cleanup:", r)
        }
}

func say(s string) {
    defer func() {
        cleanup()
        wg.Done()
    }()
    for i := 0; i < 3; i++ {
        fmt.Println(s)
        time.Sleep(time.Millisecond * 100)
        if i == 2 {
            panic("oh")
        }
    }
}

【问题讨论】:

  • 换句话说,为什么recover() 在第二种情况下会为零?提前谢谢你。

标签: go closures


【解决方案1】:

specification says:

如果满足以下任一条件,recover的返回值为nil:

...

  • recover 不是由延迟函数直接调用的。

cleanup() 函数由匿名延迟函数调用。重写代码直接推迟cleanup()

func say(s string) {
    defer wg.Done()
    defer cleanup() // cleanup called directly by defer
    for i := 0; i < 3; i++ {
        fmt.Println(s)
        time.Sleep(time.Millisecond * 100)
        if i == 2 {
            panic("oh")
        }
    }
}

【讨论】:

    【解决方案2】:

    按照规范https://golang.org/ref/spec#Handling_panics

    如果满足以下任一条件,recover的返回值为nil:

    • panic 的论点是零
    • goroutine 没有恐慌
    • recover 不是由延迟函数直接调用的。

    在您的情况下,recover 不是由延迟函数直接调用的。

    【讨论】:

      【解决方案3】:

      来自https://golang.org/pkg/builtin/#recover,我们有以下内容(强调我的):

      recover 内置函数允许程序管理恐慌 goroutine 的行为。在延迟函数(但不是由它调用的任何函数)中执行恢复调用会通过恢复正常执行来停止恐慌序列并检索传递给恐慌调用的错误值。如果在延迟函数之外调用恢复,它不会停止恐慌序列。在这种情况下,或者当 goroutine 没有恐慌时,或者如果提供给 panic 的参数是 nil,recover 返回 nil。因此,recover 的返回值报告了 goroutine 是否处于恐慌状态。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-26
        • 1970-01-01
        • 2014-09-03
        • 2013-12-04
        • 2017-02-01
        相关资源
        最近更新 更多