エラーとは?
エラーとは、例外が発生したときに発生する、抽象的な概念です。つまり、何か予期せぬことが起こる度にエラーが発生します。
エラーはどの言語にも共通して存在し、基本的にプログラミングの領域における概念であることを意味しています。
なぜエラーが必要なのか?
どんなプログラムにもエラーはつきものです。エラーは、何か予期せぬことが起きた時に異変を教えてくれます。
また、エラーはコードの安定性と保守性を維持するのに役立ちます。
なぜならエラーがなければ、今日私たちが使っているプログラムはテストが不十分になり、極めてバグが多いものになってしまうとも考えられるからです。
Golangにおけるエラー
Golangは実にシンプルな方法でエラーをサポートしています。
Golangの関数は第2の戻り値としてエラーを返します。
これがGoでエラーを実装して使う標準的な方法であり、関数を実行した後、次のステップに進む前にすぐにエラーをチェックすることができます。
変数1, 変数2 := 関数() // 変数2に関数のエラーが返る。エラーがなければnilが返る
簡単なエラーメソッド
エラーを発生させる方法は複数あります。以下では、あまり手間をかけずに作成できる簡単なものについて説明します。
New関数を使用する
GolangのerrorsパッケージにはNew()という関数があり、これを使うと簡単にエラーを作成することができます。
以下はそのコード例です。
package main
import (
"errors"
"fmt"
)
func check(v int) (int, error) {
if v == 0 {
return 0, errors.New("ゼロは使えません")
} else {
return 2 * v, nil
}
}
func main() {
result, err := check(0)
fmt.Println(result) // 0
if err != nil {
fmt.Println(err) // ゼロは使えません
}
}
Errorf関数の使用
fmtパッケージにはErrorf()メソッドがあり、以下のようなフォーマットされたエラーを作成することができます。
fmt.Errorf("Error: Zero not allowed!!! %v", v) // Error: Zero not allowed!!! 0
エラーのチェック
エラーをチェックするには、関数の2番目の戻り値を取得し、その値をnilチェックします。
エラーのゼロ値はnilなので、エラーがnilであるかどうかをチェックします。
もし2番目の戻り値がnilであればエラーは発生しておらず、それ以外の場合はエラーが発生していることになります。
package main
import (
"errors"
"fmt"
)
func e(v int) (int, error) {
return 42, errors.New("42 is unexpected!")
}
func main() {
_, err := e(0)
if err != nil { // check error here
fmt.Println(err) // 42 is unexpected!
}
}
panicとrecover
panicは予期しない間違ったことが起こったときに発生し、関数の実行を停止させます。
recoverはその反対で、実行を停止した状態から回復させることができます。
package main
import (
"fmt"
)
func createPanic(s string) {
panic(s) // panicを発生させる
}
func main() {
defer func() { // panicから回復させる
if e := recover(); e != nil {
fmt.Println("PanicからRecover!!!")
}
}()
createPanic("Panic発生!!!") // panicを発生させる関数の呼び出し
}
カスタムエラーの作成
先ほど見たように、errors.New() と fmt.Errorf() という関数を使って、新しいエラーを作成することができます。
しかし、もうひとつ別の方法があります。それは、エラーのインターフェイスを実装するやり方です。
type CustomError struct {
data string
}
func (error *CustomError) Error() string {
return fmt.Sprintf("Error occured due to... %s", error.data)
}
エラーと同時に値を返す
Goでは、エラーを返すのはとても簡単です。
Goは複数の戻り値をサポートしているので、任意の値とエラーの両方を同時に返して、エラーをチェックすることができます。
以下はそのコード例です。
package main
import (
"errors"
"fmt"
)
func returnError() (int, error) { // ここで返り値の型を定義する
return 100, errors.New("Error occured!") // return it here
}
func main() {
v, e := returnError()
if e != nil {
fmt.Println(e, v) // Error occured! 100
}
}
Golangでエラーを無視する
Goにはスキップ演算子(アンダーバー)があり、返されたエラーをスキップ(無視)することができます。
以下は、スキップ演算子を使ってエラーを無視しているコード例です。
package main
import (
"errors"
"fmt"
)
func returnError() (int, error) { // 返り値の型を定義
return 100, errors.New("Error occured!") // エラーを発生させる
}
func main() {
v, _ := returnError() // アンダーバーでエラーを無視する
fmt.Println(v) // 100
}