はじめに
こんにちは!株式会社HRBrainの25卒インターン生のizutakuです!
Goで個人開発を行っていた際、エラーハンドリングに一貫性が無いことに気づいたため、改めてエラーハンドリングの基礎を学びました。
この記事では主に以下のパッケージを使用したエラーハンドリングとカスタムエラーについて紹介しますので、ご興味があれば一読ください!
- errors
- fmt
- log
- os
errors
シンプルなエラーメッセージを持つオブジェクトを生成する。
package main
import (
"errors"
"fmt"
)
func divide(a, b int) (int, error) {
err := errors.New("cannot divide by zero") //エラーメッセージを持つオブジェクトを作成
if b == 0 {
return 0, err
}
result := a / b
return result, nil
}
func main() {
result, err := divide(100, 0)
if err != nil {
fmt.Println(err) //"cannot divide by zero"と出力される
} else {
fmt.Println(result)
}
}
出力
Cannot divide by zero
fmt
ここではfmt.Errorf()について解説する。
fmt.Sprintf()と同様に書式指定が可能となっている。
package main
import (
"fmt"
)
func divide(a, b int) (int, error) {
if b == 0 {
err := fmt.Errorf("%vでは割れません。", b)
return 0, err
}
result := a / b
return result, nil
}
func main() {
result, err := divide(100, 0)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(result)
}
}
0では割れません。
log
logではエラーメッセージや情報をログとして出力する。(logの出力先指定方法などは追々書いていく。)
logによるエラーハンドリングでは、エラー発生時に以下の動作に分けられる。
- プログラムを継続させる
- プログラムを終了させる
プログラムの継続
log.Println()、log.Printf()、log.Sprintf()などが該当する。
package main
import (
"fmt"
"log"
"os"
)
func main() {
file, err := os.Open("test.txt")
if err != nil {
log.Println(err)
}
defer file.Close()
fmt.Println("エラー出ても実行されるよ")
}
出力
2024/09/17 21:18:52 open test.txt: no such file or directory
エラー出ても実行されるよ
プログラムの終了
log.Fatal()、log.Fatalf()、log.Fatalln()が該当する。
package main
import (
"fmt"
"log"
"os"
)
func main() {
file, err := os.Open("test.txt")
if err != nil {
log.Fatalln(err)
}
defer file.Close()
fmt.Println("エラーが出たら実行されないよ")
}
出力
2024/09/17 21:19:55 open test.txt: no such file or directory
exit status 1
os
ここではos.Exit(code int)を紹介する。
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.Open("test.txt")
if err != nil {
os.Exit(20)
}
defer file.Close()
fmt.Println("エラー出たら実行されないよ")
}
出力
exit status 20
ステータスコードについて
- ステータスコードは0~125が推奨されている
- ステータスコードが0であることは、処理が正常に終了したことを示す
- ステータスコードが1~125ではエラーを示す
- ステータスコードの値は任意であり、エラーの種類(不正なフォーマット、認証失敗など)によりステタスコードを統一することでエラー改善をしやすくなる
カスタムエラー
Goではエラーインターフェース(error)を満たすカスタムエラーを定義することで、より詳細なエラー情報を得ることができる。
package main
import (
"fmt"
)
type Myerror struct {
code int
msg string
}
func (e *Myerror) Error() string {
return fmt.Sprintf("エラーコード:%d,エラーメッセージ:%s", e.code, e.msg)
}
func main() {
err := &Myerror{code: 404, msg: "ページが見つかりません"}
fmt.Println(err.Error())
}
出力
エラーコード:404,エラーメッセージ:ページが見つかりません
まとめ
今回の解説で取り上げた内容をまとめると以下のようになります。
-
fmt.Errorf()
fmt.Sprintf()のように書式指定が可能で、エラーメッセージを簡潔に作成できる。エラーを返す際に役立ちます。 -
logパッケージ
エラーや情報をログとして出力する際に使用します。log.Println()やlog.Printf()などでプログラムを継続させつつエラーを記録でき、log.Fatal()を使うとエラーメッセージを表示しつつプログラムを強制終了させることが可能です。 -
os.Exit()
指定したステータスコードを返し、プログラムを終了します。正常終了には0を、エラー終了には1~125を使用します。 -
カスタムエラー
Goではエラーインターフェースを満たすカスタムエラーを定義することで、エラーコードやメッセージを含む独自のエラーを作成できます。これにより、より詳細なエラーメッセージを提供しやすくなります。
以上を踏まえ、Goでは状況に応じた適切なエラーハンドリング方法を選択することが重要です。ログの記録やエラー内容のカスタマイズを活用することで、問題発生時のトラブルシューティングがしやすくなり、プログラムの品質向上につながります。
PR
株式会社HRBrainでは新しいメンバーを募集しています!