Help us understand the problem. What is going on with this article?

try - Go の新しいエラーハンドリング (Go 1.14で導入予定)(でしたが,却下となりました)

Go 1.14 で try というシンプルなエラーハンドリング方法が導入予定です。

2019/07/17 追記
議論の結果、try は一旦却下となりました。詳しくは提案者 Robert Griesemer 氏のコメントを参照下さい。

error

Go でのエラーハンドリングはややタイプ数が多い。

    f, err := os.Open(filename)
    if err != nil {
        return fmt.Errorf("...", err)
    }

のようなエラー処理コードを何度も書かないといけないことにストレスを感じることがあるかもしれません。

それで,去年(2018年)の GopherCon で Go 2 のドラフトデザインが発表された際,エラーハンドリングの提案が含まれていました。
checkhandle を使う提案です。

check と handle

    handle err {
        return fmt.Errorf("...", err)
    }

    f := check os.Open(filename)

戻り値の最後が error 型の場合,関数呼び出しの前に check と書けば, error が nil でない場合に handle が実行されるという提案です。
ただ,handledeferの機能が重複しているのではないか,複雑すぎるのではないか等の意見がありました。
この提案が出てから議論が重ねられ,現在,より単純化された try を使ったエラーハンドリングが Go 1.14 で導入予定になっています。

try

func FuncXXX() (err error) {
    defer func() {
        if err != nil {
            err = fmt.Errorf("...", err) 
        }
    }()
    f := try(os.Open(filename))
    // ...
    return
}

try を使う条件として,関数の返り値の最後のパラメータは error 型である必要があります。
err は関数の名前付き返り値パラメータです。err 以外の名前でもいいですし,使わないのであれば名前なしでもかまいません。

このコードは,次のコードと同等になります。

func FuncXXX() (err error) {
    defer func() {
        if err != nil {
            err = fmt.Errorf("...", err) 
        }
    }()
    t1, te := os.Open(filename)
    if te != nil {
        err = te // te を error型の返り値パラメータに代入する
        return   // try のまわりの関数 (この場合,FuncXXX) から返る 
    }
    f := t1      // エラーが発生しなかった時だけ代入が行われる
    // ...
    return
}

なお,try の導入と同時に fmt パッケージに HandleErrorf というヘルパー関数が入る予定です。
これを使えば, defer 部分は簡潔に,

    defer fmt.HandleErrorf(&err, "...")

のように書けます。

try の利点

check, handle は演算子ですが, try はビルトイン関数であることが大きな違いです。
check, handle に比べ, try にはどんな利点があるのでしょうか?

  • Go のすでにある機能 defer とビルトイン関数を使うので, 言語が複雑化しない。
  • Go に新たな構文を導入しなくてすむ。
  • 完全に後方互換性を保てる。
  • カッコを書く必要があるのはちょっと面倒に見えるかもしれないが,優先順位にあいまいなところがない。
  • try は単なる糖衣構文

簡単で Go 言語の良さを邪魔しない提案ですね。

使用例

これを使えば,以下のようなコードが書けます。

func printSum(a, b string) error {
        fmt.Println(
                "result:",
                try(strconv.Atoi(a)) + try(strconv.Atoi(b)),
        )
        return nil
}

try(strconv.Atoi(a)) + try(strconv.Atoi(b)) と 1 行で書けるのが気持ちいいです。

感想

昔話になりますが,昔はエラーは os.Error という型でした。ほぼすべてのコードで os パッケージをインポートしていました。
error ビルトイン型は大きな進歩だと感じていましたが,また一歩進みますね。
実際に Go で使えるようになる前にまだ変更が入るかもしれませんが,とても楽しみな改善です。
Generics のほうの設計も進んでいるようです。
今年の GopherCon も楽しみです!

参考

Proposal: A built-in Go error check function, try
Next steps toward Go 2
error ビルトイン型

worldhello
golang.orgのサイトを日本語に翻訳しています。https://go言語.com
https://xn--go-hh0g6u.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした