if err != nil(Goの心臓)
例外がない
多くの言語には、失敗したときに処理を中断して呼び出し元へ飛ばす仕組み(例外)があります。Go にはありません。
代わりに、失敗を戻り値で返します。
Go
func parsePrice(s string) (int, error) {
...
}前のレッスンの bool が error に変わっただけです。ただし error は理由を持てます。
受け取ったら必ず確かめる
Go
price, err := parsePrice("1200")
if err != nil {
return "読み取れませんでした"
}
// ここから先、price は信用してよいこの4行が Go で最もよく書かれる形です。エラーが nil なら成功、nil でなければ失敗です。
nil は「何も無い」を表す値です。error のゼロ値が nil なので、うまくいったときは何も返さないという形になります。
なぜこの形なのか
例外は、書かなくても勝手に飛んでいきます。楽ですが、どこで失敗しうるのか読んでも分かりません。
Go は逆です。失敗する可能性のある呼び出しは、必ず err を受け取る形になります。
Go
price, err := parsePrice(input)
if err != nil { ... }
item, err := findItem(id)
if err != nil { ... }同じ形が何度も並びます。冗長だと言われ続けている書き方でもあります。その代わり、失敗する場所が全部目に見えます。読み飛ばせません。
if の初期化文が効く
第3章で触れた、条件の前に文を置ける if がここで生きます。
Go
if _, err := parsePrice(input); err != nil {
return "読み取れませんでした"
}err がこの if の中だけの変数になり、後ろに残りません。値のほうが要らないときに使う形です。
やってはいけない書き方
Go
price, _ := parsePrice(input) // エラーを捨てている_ でエラーを捨てると、失敗しても気づけません。price にはゼロ値の 0 が入り、そのまま計算に使われます。
Go で最も嫌われる書き方です。 捨ててよいのは、失敗しないと確信できる場合か、失敗しても本当に困らない場合だけです。そしてその判断は、たいてい間違っています。
エラーは値である
error は特別な構文ではなく、ただの型です。変数に入れて持ち回ることも、まとめて返すこともできます。
Go
var err error // ゼロ値は nil「エラーは値である」という言い方を Go の界隈でよく聞きます。特別扱いしないことが、この言語の一貫した態度になっています。
要件
validatePriceの戻り値をerrで受け取るerr != nilのときは登録できませんを返す- エラーが無ければ
N円で登録できますを返す
入出力例
checkPrice(1200) → "1200円で登録できます"
checkPrice(0) → "登録できません"
checkPrice(-100) → "登録できません"
checkPrice(1000000) → "1000000円で登録できます"
checkPrice(1000001) → "登録できません"