13

有没有办法清理这个(IMO)看起来很可怕的代码?

    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
} 

具体来说,我说的是错误处理。能够一口气处理所有错误会很好。

4

5 回答 5

19
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
于 2013-03-13T22:21:02.900 回答
14

将结果放在一个切片而不是变量中,将初始值放在另一个切片中进行迭代,如果出现错误则在迭代期间返回。

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
    }
}

当然,这需要一个类型断言来使用结果。

于 2013-03-13T22:18:02.167 回答
7

定义一个函数。

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
}

你没有说你希望你的错误处理如何工作。失败一个,失败所有?第一个失败?收集成功还是扔掉它们?

于 2013-03-13T22:28:14.163 回答
5

我相信这里的其他答案对于您的特定问题是正确的,但更一般地说,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 并专门处理每个错误。另一个缺点是它可以防止应该恐慌的东西真正恐慌。(但这可以通过使用您自己的错误类型轻松解决。)

于 2013-03-14T17:59:44.890 回答
1

您可以创建一个可重用的方法,然后仅在一个 if 条件下捕获错误。这个实现只会显示最后一个错误。

func hasError(errs ...error) error {
    for i, _ := range errs {
        if errs[i] != nil {
            return errs[i]
        }
    }
    return nil
}

aJson, err := 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, err7 := json.Marshal(g)

if error := util.hasError(err, err1, err2, err3, err4, err5, err6, err7); error != nil {
    return error
}
于 2021-02-03T14:05:02.427 回答