Go - 优雅地处理多个错误?
问题描述:
有没有办法清理这个(IMO)可怕的代码?Go - 优雅地处理多个错误?
aJson, err1 := json.Marshal(a)
bJson, err2 := json.Marshal(b)
cJson, err3 := json.Marshal(c)
dJson, err4 := json.Marshal(d)
eJson, err5 := json.Marshal(e)
fJson, err6 := json.Marshal(f)
gJson, err4 := json.Marshal(g)
if err1 != nil {
return err1
} else if err2 != nil {
return err2
} else if err3 != nil {
return err3
} else if err4 != nil {
return err4
} else if err5 != nil {
return err5
} else if err5 != nil {
return err5
} else if err6 != nil {
return err6
}
具体来说,我在谈论错误处理。能够一次处理所有错误将会很好。
答
var err error
f := func(dest *D, src S) bool {
*dest, err = json.Marshal(src)
return err == nil
} // EDIT: removed()
f(&aJson, a) &&
f(&bJson, b) &&
f(&cJson, c) &&
f(&dJson, d) &&
f(&eJson, e) &&
f(&fJson, f) &&
f(&gJson, g)
return err
答
将结果放入切片而不是变量中,如果存在错误,则将迭代中的初始值放入另一个切片中进行迭代和返回。
var result [][]byte
for _, item := range []interface{}{a, b, c, d, e, f, g} {
res, err := json.Marshal(item)
if err != nil {
return err
}
result = append(result, res)
}
你甚至可以重复使用数组而不是两片。
var values, err = [...]interface{}{a, b, c, d, e, f, g}, error(nil)
for i, item := range values {
if values[i], err = json.Marshal(item); err != nil {
return err
}
}
当然,这将需要一个类型断言来使用结果。
答
定义了一个函数。
func marshalMany(vals ...interface{}) ([][]byte, error) {
out := make([][]byte, 0, len(vals))
for i := range vals {
b, err := json.Marshal(vals[i])
if err != nil {
return nil, err
}
out = append(out, b)
}
return out, nil
}
你没有说你希望你的错误处理如何工作。失败一个,全部失败?首先失败?收集成功或折腾他们?
答
我相信这里的其他答案对你的具体问题是正确的,但更一般地说,panic
可以用来缩短错误处理,同时仍然是一个行为良好的库。 (即,不panic
荷兰国际集团跨越包边界)
考虑:
func mustMarshal(v interface{}) []byte {
bs, err := json.Marshal(v)
if err != nil {
panic(err)
}
return bs
}
func encodeAll() (err error) {
defer func() {
if r := recover(); r != nil {
var ok bool
if err, ok = r.(error); ok {
return
}
panic(r)
}
}()
ea := mustMarshal(a)
eb := mustMarshal(b)
ec := mustMarshal(c)
return nil
}
该代码使用mustMarshal
到panic
每当有一个编组值的问题。但encodeAll
函数将recover
从恐慌和返回它作为一个正常的错误值。在这种情况下,客户永远不会感到恐慌。
但是这带来了一个警告:在任何地方使用这种方法都不是惯用的。它也可能更糟糕,因为它不能很好地处理每个单独的错误,但是或多或少地将每个错误视为相同。但是当有大量错误需要处理时,它就有其用处。例如,我在Web应用程序中使用这种方法,其中顶级处理程序可以捕获不同类型的错误,并根据错误类型将它们适当地显示给用户(或日志文件)。
当有很多错误处理时,它使得代码更加准确,但是在丢失了惯用的Go和专门处理每个错误时。另一个不利的方面是它可以防止恐慌实际上发生恐慌。 (但这可以通过使用你自己的错误类型来解决。)
标题是关于错误处理,但你似乎正在返回它们而不是[恐慌()](http://golang.org/doc /effective_go.html#panic),这是为什么?马歇尔一失败就马上不立即回国? – Deleplace 2013-03-13 23:39:00
为什么我会使用panic()而不是返回错误?从链接到的文档中:“向调用者报告错误的常用方法是将错误作为额外的返回值返回。”我觉得这是一个“常见”的情况。使用panic()感觉是合理的,这不是严重的错误。 (如果我误解了恐慌函数的用例,请纠正我。) – 2013-03-13 23:54:02
我知道你已经注意到了每个gopher会同意什么,不使用/滥用恐慌,但上面的代码示例非常糟糕/模糊。把所有东西都编成数字,但只返回我们之后看到的第一个错误?但是,接下来你会澄清“一次处理所有错误”,通常会使代码示例无效。这又取决于你的行为,恐慌/恢复可能是合适的。就我个人而言,我会立即在一位失败的元帅身上发现错误,并更具描述性地指出“cJson”失败,并附有“err”。但即使如此,仍取决于所运行的环境。 – dskinner 2013-03-14 14:02:12