• Goは関数からerror型を戻すことによりエラーを処理する
    • 関数が期待通りに実行された場合はerrorにはnilが返される
    • 何かがうまくいかない場合はerror型の値が返される
    • 呼び出し側では、errorの戻り値をnilと比較することでチェックし、そのエラーを処理したり独自のエラーを返したりする
package main
 
import (
	"errors"
	"fmt"
	"os"
)
 
func main() {
	numerator := 20
	denominator := 0
	// 除数が0なのでerrにエラーメッセージがdenominator is 0が入って戻される
	remainder, mod, err := calcRemainderAndMod(numerator, denominator)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	fmt.Printf("%d÷%d: 商:%d, 余り: %d\n", numerator, denominator,
		remainder, mod)
}
 
func calcRemainderAndMod(numerator, denominator int) (int, int, error) {
	// 被除数と除数をもらって、商と余り、それにerrorを返す
	if denominator == 0 {
		return 0, 0, errors.New("denominator is 0") // 除数が0
	}
 
	return numerator / denominator, numerator % denominator, nil
}
 
  • Goで他の言語のように例外をスローせず、エラーを返す理由は少なくとも2つある
    • 例外があるとコードの道(パス)が少なくとも1本増えてしまうため
      • 例外パスがわかりにくい場合がある
      • 例外が適切に処理されないとクラッシュを引き起こす
      • もしくはデータが適切に初期化・変更・保存されないコードになってしまうため
    • 安全性・可読性を上げるため
      • Goのコンパイラは全ての変数が読まれることを強要するので、エラーの際に値が戻されることで以下の利点がある
        • エラーをチェックし処理する
        • _を使って、エラーの無視を明示する
      • エラー処理はif文の内部にインデントして書かれ、ビジネスロジックはインデントされない。この違いにより、どのコードが主要な処理でどのコードが例外的な状況なのか視覚的に説明できる