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

2つのスライスを使用する代わりに、配列を再利用することもできます。

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
}

エラー処理をどのように機能させたいかについては何も言わなかった。1つ失敗し、すべて失敗しますか?最初に失敗しますか?成功を集めるか、それとも投げますか?

于 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が失われ、各エラーが特別に処理されます。もう1つの欠点は、パニックになるはずの何かが実際にパニックになるのを防ぐことができることです。(ただし、これは独自のエラータイプを使用することで簡単に解決できます。)

于 2013-03-14T17:59:44.890 に答える
1

再利用可能なメソッドを作成し、if条件でエラーを1つだけキャッチできます。ただし、この実装では最後のエラーのみが表示されます。

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 に答える