英文:
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)
}
输出:
"返回值", <nil>(<nil>)
"", *errors.errorString(&errors.errorString{s:"失败"})
"", *errors.errorString(&errors.errorString{s:"42"})
"", runtime.errorString("integer divide by zero")
英文:
For example:
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 "returned", nil
}
func B(s string) {
switch s {
case "ok":
return
case "fail":
panic(errors.New("failed"))
case "fail miserably":
panic(42)
default:
a, b := 1, 0
if a/b != 0 {
panic("ouch")
}
}
}
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)
}
Output:
"returned", <nil>(<nil>)
"", *errors.errorString(&errors.errorString{s:"failed"})
"", *errors.errorString(&errors.errorString{s:"42"})
"", runtime.errorString("integer divide by zero")
答案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
...
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论