Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Goのerror型がシンプルであることの恩恵について理解する

 Goのerror型がシンプルであることの恩恵について理解する

# 今日のまとめ
- Goはerrorを値として扱い、順次処理と分岐だけでエラー処理を実現
- 一方で冗長という意見もあるが、Goチームは構文変更せず現状維持の方針(2025年6月時点)
- シンプルさが「制御フローの明確さ」を保証している

Avatar for yamatai12

yamatai12

March 19, 2026
Tweet

More Decks by yamatai12

Other Decks in Technology

Transcript

  1. Goのerror型 Goではerrorを値として扱う type error interface { Error() string } 関数は複数戻り値で

    error を返し、呼び出し側が直後にエラー処理をする result, err := doSomething() if err != nil { return err } 参考: https://go.dev/blog/errors-are-values 5
  2. try-catch-finallyとの比較 tryブロック内のどの関数からでも例外がスローされる可能性があり、制御フローが暗 黙的にcatch/finallyへジャンプする try { a(); b(); // ← ここで例外が投げられたら…

    c(); // ← ここはスキップされて } catch (e) { // ← いきなりここに飛んでくる } finally { // ← さらにここも通る } We believe that coupling exceptions to a control structure, as in the try-catch-finally idiom, results in convoluted code. https://go.dev/doc/faq#exceptions 6
  3. 冗長性の課題と改善の試み(1/3) err != nil が多用され、ロジックが埋もれるという意見がある func printSum(a, b string) error

    { x, err := strconv.Atoi(a) if err != nil { return err }//エラー処理 y, err := strconv.Atoi(b) if err != nil { return err }//エラー処理 fmt.Println("result:", x + y) return nil } 8
  4. 冗長性の課題と改善の試み(2/3) Goチームの取り組み: 2018年: check/handle → 複雑すぎると判断 2019年: try → 制御フローを隠してしまうため不採用

    2024年: ? 演算子 → 採用に至らず 参考: https://go.dev/blog/error-syntax 本スライドの16ページ以降でも各案について説明 9
  5. 冗長性の課題と改善の試み(3/3) ? 演算子 (2024) 式の末尾に ? を付けてエラーチェック。Rustの ? 演算子に着想を得たもの 失敗したら早期returnする

    func printSum(a, b string) error { x := strconv.Atoi(a) ? y := strconv.Atoi(b) ? fmt.Println("result:", x + y) return nil } https://github.com/golang/go/issues/71203 10
  6. 冗長性は本当に問題か? エラーに追加情報を付与すると、boilerplate感は弱くなり、意味のあるロジックになる x, err := strconv.Atoi(a) if err != nil

    { //return err ← before return fmt.Errorf("invalid integer: %q", a)// ← after } 他の言語から来た直後は冗長に感じるが、Goに慣れると気にならなくなる Many mentioned that the lack of specific error handling support in Go is most apparent when coming freshly from another language that has that support. As one becomes more fluent and writes more idiomatic Go code, the issue becomes much less important. https://go.dev/blog/error-syntax#:~:text=On a final,another data point. 11
  7. Goチームの現在の方針 2025年6月: エラー処理の構文変更を当面中止 For the foreseeable future, the Go team

    will stop pursuing syntactic language changes for error handling. 当面の間、Goチームはエラー処理に関する構文変更の検討を中止します。 → シンプルさを維持することで制御フローの明確さを保つ判断 12
  8. check/handle (2018) checkでエラーを検査し、エラーがあればhandleブロックで処理する func printSum(a, b string) error { handle

    err { return err } x := check strconv.Atoi(a) y := check strconv.Atoi(b) fmt.Println("result:", x + y) return nil } → 複雑すぎると判断され不採用 https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling- overview.md 17
  9. try (2019) 組み込み関数tryでエラーがnilでなければ即座にreturnする。エラーの加工はdeferで行 う func printSum(a, b string) error {

    x := try(strconv.Atoi(a)) y := try(strconv.Atoi(b)) fmt.Println("result:", x + y) return nil } → 制御フローが見えづらくなると判断され不採用 https://github.com/golang/go/issues/32437 18
  10. errorは値 → 構造体に保持して冗長さを減らす 参考: https://go.dev/blog/errors-are-values type errWriter struct { w

    io.Writer err error } func (ew *errWriter) write(buf []byte) { if ew.err != nil { return } // エラー後はスキップ _, ew.err = ew.w.Write(buf) } //呼び出し側 ew := &errWriter{w: fd} ew.write(p0[a:b]) ew.write(p1[c:d]) // if err != nil が不要 ew.write(p2[e:f]) if ew.err != nil { return ew.err } // 最後に1回だけチェック 標準ライブラリの bufio.Writer でも同じパターンが使われている 19