ホームページ  >  記事  >  バックエンド開発  >  試してみてください。新しい提案は信頼できますか?エラー処理を簡素化したい

試してみてください。新しい提案は信頼できますか?エラー処理を簡素化したい

Golang菜鸟
Golang菜鸟転載
2023-08-04 17:05:371257ブラウズ


#最近の新しい try プロポーザル「

プロポーザル: Go 2: エラー処理: ハンドラーを使用した try ステートメント[1]#」 ##》はコミュニティ内で白熱した議論を巻き起こしました。もう一度コミュニティと戦いましょう! ! ! 今日、Jianyu はこれを全員と一緒に公開し、これによって Go エラー処理メカニズムが開かれ、再編成できるかどうかを確認します。

背景提案作成者である PingCAP の @Greg Weber は 2 つの要素に基づいてこれを行います。1 つは「

Go 開発者アンケート 2022 年第 2 四半期の結果#」にあります。

##[2]」と明記されています。

Go1.18 ジェネリックのリリースにより、元の最も矛盾したジェネリックが暫定的な解決策を受け取りました。コミュニティの調査によると、Go を使用する際に開発者が直面する最大の課題はエラー処理に移行しており、それを「解決」するにはエネルギーを投資する必要があります。 試してみてください。新しい提案は信頼できますか?エラー処理を簡素化したい
もう 1 つの要因は、Go のエラー処理コードが比較的面倒であることがよく知られているということであり、エンジニアはよく Go プロジェクトの 30% に if err = nil があると冗談を言います。

次のコード:

_, err := f()
if err != nil {
    ...
}
_, err = r()
if err != nil {
    ...
}
_, err = w()
if err != nil {
    ...
}

もっとエレガントにしたいと思っています。多くの友人もこのデザインに同意しており、実にシンプルで直感的な処理であるため、コミュニティ内で論争が巻き起こっています。

try-handler 提案

この提案で言及されている解決策は、簡潔なエラー処理を実現するために新しいステートメントを追加することです。スムーズ。

次のコード:

try err, handler

コンパイラによる変換後に生成されるコード:

if err != nil {
    return handler(err)
}

関数内では、次のようになります:

func(args...) (rtype1, rtypes..., rtypeN, error) {
    try err, handler
    ...
}

変換後に生成されたコード:

func(args...) (rtype1, rtypes..., rtypeN, error) {
    if err != nil {
            return Zero(rtype1), Zeros(rtypes...)..., Zero(rtypeN), handler(err)
    }
    ...
}

これは、err != nil の場合にのみ処理することもできます。次のコード:

try err

翻訳されたコード:

if err != nil {
    return err
}

は、存在しないハンドラーを呼び出して処理を行わず、直接戻ります。 3 行 (if err != nil ロジック) は 3 つのワードを直接変更します (試してください)。

関数を書きたくない場合は、直接記述することもできます:

x, err := f()
try err, fmt.Errorf("f fail: %w", err)

遅延試行のシナリオは次のとおりです:

func CopyFile(src, dst string) error {
    defer try func(err error) error {
        return fmt.Errorf("copy %s %s: %w", src, dst, err)
    }
    ...
}

入力パラメータは次のとおりです。これにより、さまざまなシナリオの要件に適応できるようになります。

示例和实践

针对本提案,原作者给出了各类使用场景的示例。如下代码:

import (
    "fmt"
)

// This helper should be defined in the fmt package
func Handlew(format string, args ...any) func(error) error {
 return func(err error) error {
  args = append(args, err)
  return fmt.Errorf(format+": %w", args...)
 }
}

// This helper should be defined in the fmt package
func Handlef(format string, args ...any) func(error) error {
 return func(err error) error {
  args = append(args, err)
  return fmt.Errorf(format+": %v", args...)
 }
}

func valAndError() (int, error) {
    return 1, fmt.Errorf("make error")
}

func newGo() (int, error) {
    x, err := valAndError()
    try err

    // Common formatting functions will already be provided
    i := 2
    x, err = valAndError()
    try err, Handlew("custom Error %d", i)

    // Using a custom error type
    // For convenience the error type can expose a method to set the error
    x, err = valAndError()
    try err, TheErrorAsHandler(i)
}

type TheError struct{
    num int
    err error
}

func (t TheError) Error() String {
    return fmt.Sprintf("theError %d %v", t.num, t.err)
}

func TheErrorAsHandler(num int) func(err) TheError {
    return func(err error) TheError {
        return theError{ num: i, err: err }
    }
}

另外在日常的 Go 工程中,提案作者认为 CopyFile 函数是新提案语句的一种很好的实践。为此基于 try-handler 进行了一版改造和说明。

如下代码:

// This helper can be used with defer
func handle(err *error, handler func(err error) error) {
    if err == nil {
        return nil
    }
    *err = handler(err)
}

func CopyFile(src, dst string) (err error) {
    defer handle(&err, func(err error) error {
        return fmt.Errorf("copy %s %s: %w", src, dst, err)
    })

    r, err := os.Open(src)
    try err
    defer r.Close()

    w, err := os.Create(dst)
    try err, func(err error) error {
            os.Remove(dst) // only if Create fails
            return fmt.Errorf("dir %s: %w", dst, err)
    }
    defer w.Close()

    err = io.Copy(w, r)
    try err
    err = w.Close()
    try err
    return nil
}

引入 try-hanlder 后,能够做到:

  • 插入错误的返回语句,进行机制预设。
  • 在返回错误之前将错误处理函数组合在一起,便于后续的处理。

总结

在这个新提案中,一旦实施,就可以减少如下代码的编写:

if err != nil {
  return ...
}

在代码编写上会节省一些行数,且可以为错误处理机制引入一些新的 ”操作“,这是该提案的优势。

但是从 Go 开发者的角度而言,会引入一些新的副作用,例如:初学者的学习成本、Go 工具链的改造、程序理解的复杂度增加。

另外新的语句,似乎比较难与 Go1.13 引入的 error.Is 和 As 有较好的相关联性。如果是做一个第三方用户库引入倒可以,但若是作为标准进入 Go 源代码中,似乎又有些格格不入(提案作者希望进入)。

看了那么多提案,Go 错误处理机制的 ”升级“,似乎陷入了手心手背都是肉的阶段...

以上が試してみてください。新しい提案は信頼できますか?エラー処理を簡素化したいの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はGolang菜鸟で複製されています。侵害がある場合は、admin@php.cn までご連絡ください。