在GO语言中,在延迟函数中使用panic()函数的参数。

huangapple go评论107阅读模式
英文:

getting panic() argument in defer function in GO lang

问题

我有一个函数A调用函数B,有时会根据无效数据调用panic。
在函数A的延迟函数中,我想知道函数B传递给panic()的消息,这样我就可以将错误以JSON格式通过网络返回给客户端。

例如:

func A(abc data) result string{
  defer func(){
    // 获取panic参数并返回结果。
  }

  xx = B(abc[0]);
  yy = B(abc[1]);
  ...
}

函数B使用panic的原因是为了避免在函数A中使用大量的

err := B(abc)
if err != nil {
    ...
}

并使代码更易于阅读和维护。

英文:

I have a function A calling function B which would sometime call panic based on invalid data.
In function A defer function, I would like to know the message function B passed to the panic() so that I can report the error in json over the network back to the client.

e.g.

func A( abc data) result string{
  defer func(){
    // get panic args and return result.
  }

  xx = B( abc[0] );
  yy = B( abc[1] );
  ...
}

The reason function B use panic is to avoid a very large amount of

err := B(abc)
if err != nil {
    ...
}

in function A and make the code easier to read and maintain.

答案1

得分: 4

例如:

package main

import (
        "errors"
        "fmt"
)

func A(s string) (result string, err error) {
        defer func() {
                if e := recover(); e != nil {
                        switch x := e.(type) {
                        case error:
                                err = x
                        default:
                                err = fmt.Errorf("%v", x)
                        }
                }
        }()

        B(s)
        return "返回值", nil
}

func B(s string) {
        switch s {
        case "ok":
                return
        case "fail":
                panic(errors.New("失败"))
        case "fail miserably":
                panic(42)
        default:
                a, b := 1, 0
                if a/b != 0 {
                        panic("糟糕")
                }
        }
}

func main() {
        s, err := A("ok")
        fmt.Printf("%q, %T(%#v)\n", s, err, err)

        s, err = A("fail")
        fmt.Printf("%q, %T(%#v)\n", s, err, err)

        s, err = A("fail miserably")
        fmt.Printf("%q, %T(%#v)\n", s, err, err)

        s, err = A("")
        fmt.Printf("%q, %T(%#v)\n", s, err, err)
}

Playground


输出:

"返回值", <nil>(<nil>)
"", *errors.errorString(&errors.errorString{s:"失败"})
"", *errors.errorString(&errors.errorString{s:"42"})
"", runtime.errorString("integer divide by zero")
英文:

For example:

package main

import (
        &quot;errors&quot;
        &quot;fmt&quot;
)

func A(s string) (result string, err error) {
        defer func() {
                if e := recover(); e != nil {
                        switch x := e.(type) {
                        case error:
                                err = x
                        default:
                                err = fmt.Errorf(&quot;%v&quot;, x)
                        }
                }
        }()

        B(s)
        return &quot;returned&quot;, nil
}

func B(s string) {
        switch s {
        case &quot;ok&quot;:
                return
        case &quot;fail&quot;:
                panic(errors.New(&quot;failed&quot;))
        case &quot;fail miserably&quot;:
                panic(42)
        default:
                a, b := 1, 0
                if a/b != 0 {
                        panic(&quot;ouch&quot;)
                }
        }
}

func main() {
        s, err := A(&quot;ok&quot;)
        fmt.Printf(&quot;%q, %T(%#v)\n&quot;, s, err, err)

        s, err = A(&quot;fail&quot;)
        fmt.Printf(&quot;%q, %T(%#v)\n&quot;, s, err, err)

        s, err = A(&quot;fail miserably&quot;)
        fmt.Printf(&quot;%q, %T(%#v)\n&quot;, s, err, err)

        s, err = A(&quot;&quot;)
        fmt.Printf(&quot;%q, %T(%#v)\n&quot;, s, err, err)
}

Playground


Output:

&quot;returned&quot;, &lt;nil&gt;(&lt;nil&gt;)
&quot;&quot;, *errors.errorString(&amp;errors.errorString{s:&quot;failed&quot;})
&quot;&quot;, *errors.errorString(&amp;errors.errorString{s:&quot;42&quot;})
&quot;&quot;, runtime.errorString(&quot;integer divide by zero&quot;)

答案2

得分: 0

你想要的是recover函数。你希望将其延迟执行是正确的做法 - recover只在延迟函数中才能正常工作(如果你在函数体中调用它,它要么返回nil(如果没有发生恐慌),要么在发生恐慌时被跳过)。recover会返回被恐慌的值,类型为空接口:

func A(abc data) result string {
    defer func() {
        p := recover() // p是一个空接口值,如果没有发生恐慌,它将为nil
    }() // 你必须调用这个函数
    ...
}
英文:

What you want is the recover function. You're right to want to defer it - recover only works properly in a deferred function (if you call it in the body, it will either return nil if there was no panic, or get skipped over when a panic does happen). Recover returns the value that was panicked in an empty interface:

func A(abc data) result string {
    defer func() {
        p := recover() // p is an interface{} value, and will be nil if there was no panic
    }() // You have to call the function
    ...
}

huangapple
  • 本文由 发表于 2013年8月15日 23:08:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/18255665.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定