エラー処理
読了目安 約3分
失敗が日常である本番のコードで、Go が例外ではなく値としてエラーを扱う理由と、if err != nil の慣習を学びます。
この章の目次
競プロの入力は問題文の制約を必ず満たすので、失敗の処理を書かずに済みました。 本番の Web サービスには、この前提がありません。
失敗するのが普通の世界
ネットワークは切れ、データベースは応答を返さず、ユーザーは年齢の欄に「二十八」と入力してきます。 これらは日常なので、本番のコードは失敗時の処理を成功時と同じ比重で書きます。
値としての error
多くの言語は失敗を例外(throw と try-catch)で表しますが、Go は普通の値で表します。 error は「失敗したかどうか、失敗したならその内容」を表す型で、失敗しうる関数が最後の戻り値として返します(成功時は nil)。
package main
import (
"fmt"
"strconv"
)
func main() {
for _, s := range []string{"42", "abc", ""} {
n, err := strconv.Atoi(s)
if err != nil {
fmt.Printf("%q の変換に失敗: %v\n", s, err)
continue
}
fmt.Printf("%q の変換に成功: %d\n", s, n)
}
}strconv.Atoi は文字列を int に変換する関数で、失敗すると 2 つ目の戻り値にエラーを返します。
この「err を調べて対処する」形が、Go のエラー処理の基本です。
if err != nil という慣習
Go のコードには、この 3 行が繰り返し現れます。
n, err := strconv.Atoi(s)
if err != nil {
return err // 自分では対処できないので、呼び出し元に返す
}冗長に見えますが、失敗の可能性がコードの見た目に現れ、例外のように処理を飛び越えて伝わることがありません。
エラーを握りつぶすとどうなるか
エラーは _ に代入すれば無視できてしまいます。
n, _ := strconv.Atoi(s) // 失敗しても n = 0 のまま処理が続くこの書き方をエラーの握りつぶしと呼びます。 握りつぶした失敗はゼロ値として下流に流れ、症状は遠く離れた場所で出ます(「なぜか残高が 0 円で登録されている」)。 原因の行を探す調査に、時間を取られます。
fmt.Errorf と %w で文脈を付ける
そのまま返すだけだと、最上位に届いた「invalid syntax」からは何の変換の失敗かわかりません。 fmt.Errorf は書式付きでエラーを作る関数で、%w を使うと元のエラーを包んだまま説明を足せます。
package main
import (
"errors"
"fmt"
"strconv"
)
func parseAge(s string) (int, error) {
n, err := strconv.Atoi(s)
if err != nil {
return 0, fmt.Errorf("年齢の解析に失敗: %w", err)
}
if n < 0 {
return 0, errors.New("年齢が負の値です")
}
return n, nil
}
func main() {
for _, s := range []string{"28", "-3", "abc"} {
age, err := parseAge(s)
if err != nil {
fmt.Println("エラー:", err)
continue
}
fmt.Println("年齢:", age)
}
}%w で包む(ラップする)と、外側の関数が「どの処理の途中だったか」を足し、内側のエラーが「直接の原因」を保ちます。
panic は本当に異常なときだけ
Go にも panic という、プログラムを即座に停止させる仕組みがあります。 これはプログラムのバグのためのもので、ユーザー入力の不正やネットワークの失敗を panic で扱うわけにはいきません。
1 つのプログラムが全ユーザーからのアクセスを処理しているので、1 人の入力で止めれば無関係な全ユーザーも道連れになるからです。 起こりうる失敗は、すべて error で返します。
試してみよう
上の parseAge を、次の順に書き換えてください。
- 151 以上の値もエラーにする(メッセージは「年齢が大きすぎます」など)。
mainのループに"200"を足して、追加したエラーが出ることを確かめる。- 最後に、
strconv.Atoiの行をn, _ := strconv.Atoi(s)に変えて、"abc"がどう扱われるかを観察する。エラーの握りつぶしを、その目で確かめられます。