Go言語のコードを書いている時に意図的にエラー型を生成したい時がある
例えば、os.Openやos.Createの関数などはerrorを返す関数になっています。このようなerrorが自然に発生する場合にはerrorを意図的に生成する必要がありません。
しかし、コードを書いていると、errorを意図的に生成したいタイミングがあります。
エラーが自然に発生しないパターンの例
- string型の引数が空文字の場合、errorを返したい時
▼サンプルコード
func exampleFunc(str string) error{
if str == "" {
panic("empty string") //本当はerrorを返したい!
}
return nil
}
- switch文のdefaultでpanicではなく、errorを返したい時
▼サンプルコード
func exampleFunc(flag int) error{
switch(flag) {
case 1:
fmt.Println("case 1")
case 2:
fmt.Println("case 2")
case 3:
fmt.Println("case 3")
default:
panic("invalid flag") //本当はエラーを返したい!
}
return nil
}
そもそもerror型とは何か?
error型とはそもそもどんな型なのかをまずは整理します。
- error型はビルトインのインターフェース型の一つ。
▼定義
type error interface {
Error() string
}
- よく使われている「error」はerrorsパッケージにて実装されたerrorString構造体
type errorString struct {
s string
}
func (e *errorString) Error() string {
return e.s
}
- インターフェースであるため、このインターフェースを実装する構造体を定義すれば、独自定義のエラーを実装することも可能。
▼サンプルコード
// 構造体を定義
type MyError struct {
message string
code string
}
// Errorメソッドを実装。(Error型で決められたインターフェースを実装、満たす)
func (m MyError)Error() string {
return m.code + " : " + m.message
}
// 実際に独自定義したMyErrorを呼び出してみる
func exampleFunc(str string) error{
var err MyError
if str == "" {
err.code = "500"
err.message = "internal server error"
fmt.Println("check Error():", err.Error())
return err
}
fmt.Println("str:", str)
return nil
}
エラー型を意図的に生成する方法
エラー変数を意図的に生成する主な方法は下記2つあるようです。それぞれメリットについてもまとめてみました。
方法1:errors.New()関数を利用する
- errors.New()は引数にエラーメッセージとなる文字列を受け取り、エラー型を返す
- エラーメッセージをカスタマイズしたい場合は、事前にエラーメッセージとなる文字列を作っておく必要がある
package main
import (
"errors"
"fmt"
"log"
)
func exampleFunc(str string) error{
if str == "" {
err := errors.New("エラーです")
return err
}
return nil
}
func main(){
emptyStr := ""
err := exampleFunc(emptyStr)
if err != nil {
log.Fatal(err) //出力例:2022/xx/xx xx:xx:xx エラーです
}
fmt.Println("success")
}
▼メリット
- 既にエラー出力したい文字列が用意されている時には便利
- シンプルなエラーを生成したい時に便利
方法2:fmt.Errorf()関数を利用する
- fmt.Errorf()はfmt.Sprintf()のようにフォーマットを指定したエラーメッセージを持つerror型を生成する。
package main
import (
"fmt"
"log"
)
func exampleFunc(str string) error{
if str == "" {
err := fmt.Errorf("%s", "エラーです")
return err
}
return nil
}
func main(){
emptyStr := ""
err := exampleFunc(emptyStr)
if err != nil {
log.Fatal(err) //出力例:2022/xx/xx xx:xx:xx エラーです
}
fmt.Println("success")
}
▼メリット
- やはりフォーマット指定でエラー文字列をカスタマイズできること。fmt.Sprintfと同じような感覚で利用できる。
- 記述量は少なくできるかも。
結論:errors.New()とfmt.Errorf()はどちらがいい?
正直、あまり変わらない印象なので、どちらでもご自身がしっくりくる方でいいと思います!
記述量を少なくしたい場合は、fmt.Errorf()の方が少なくなりそうです。
参考文献
https://astaxie.gitbooks.io/build-web-application-with-golang/content/ja/11.1.html