はじめに
goをさわって数ヶ月ですが、雰囲気では書けていたものの
errorやエラーハンドリングについてはもやもやしたままだったので自分理解メモの①
関連
この記事の関連です。
アジェンダ
- errorの基本の書き方
- Error型について
- 任意の文字列でError型を返す(errors.Newとfmt.Error)
- カスタムError
1. errorの基本の書き方
以下のコードがerrorについての基本です。
// Openに成功したらnil(エラー無し)が返される // Openに失敗したらerror側の値が返却される f, err := os.Open("filename.ext") if err != nil { log.Fatal(err) }
返されるerror変数とnilを比較することで操作が成功したか判断します。
上記で言えば if err != nil {
です。
os.Open
の定義は以下のようになっています。
func Open(name string) (file *File, err error)
https://golang.org/pkg/os/#Open
2. Error型について
errorはgoのビルトインのインターフェース型の1つです。
type error interface { Error() string }
多くの内部パッケージにおいて使用されるerrorは
errorsパッケージ以下で実装されたプライベート構造体errorStringらしいです。
// Package errors implements functions to manipulate errors. package errors // New returns an error that formats as the given text. func New(text string) error { return &errorString{text} } // errorString is a trivial implementation of error. type errorString struct { s string } func (e *errorString) Error() string { return e.s }
使う場合は、errors.New
を通して文字列をerrorStringに変換し
インターフェースerrorを満たすオブジェクトを得る、という感じになってます。
3. 任意の文字列でError型を返す(errors.Newとfmt.Error)
Error型について触れましたが、任意の文字列でerror型を返すには主に以下の2つがメジャーです。
- errors.New
- fmt.Error
用途としての大きな違いは、
fmt.Errorはフォーマットを指定したエラーを返せる
ので
固定文字列でよければerrors.New
、可変文字列を含めたければfmt.Error
という感じでしょうか。
以下で使ってみます。
errors.New
errors.Newに文字列を渡すだけです。
サンプル
https://github.com/tweeeety/go-error/blob/master/src/go-error/sample01/main.go
package main import ( "errors" "fmt" ) func errorsNewSsample() error { err := errors.New("this is errors.New sample.") return err } func main() { err := errorsNewSsample() fmt.Println(err) fmt.Printf("%T\n", err) }
出力
$ go run src/go-error/sample01/main.go this is errors.New sample. *errors.errorString
fmt.Error
フォーマット文字列を渡せるので、変数の値を一緒に出したい場合などに使います。
サンプル
https://github.com/tweeeety/go-error/blob/master/src/go-error/sample02/main.go
package main import ( "fmt" ) func fmtErrorfSsample(str string) error { err := fmt.Errorf("this is fmt.Errorf sample. str: %s", str) return err } func main() { err := fmtErrorfSsample("hogehoge") fmt.Println(err) fmt.Printf("%T\n", err) }
出力
$ go run src/go-error/sample02/main.go this is fmt.Errorf sample. str: hogehoge *errors.errorString
4. カスタムError
2. Error型について
で触れた通り
errorインターフェース満たすにはError()
を実装すれば良いです。
この方法で任意のカスタムError型を作ります。
sample01/main.go
package main import ( "fmt" ) // カスタムErrorの構造体 type MyError struct { Msg string Code int } // error interfaceを実装 func (err *MyError) Error() string { return fmt.Sprintf("ERROR: %d %s", err.Code, err.Msg) } // 何かする処理 func doSomething() error { return &MyError{Msg: "doSomething is unexpected error", Code: 30001} } func main() { if err := doSomething(); err != nil { fmt.Println(err) fmt.Printf("%T\n", err) } }
出力
$ go run src/go-error/sample03/main.go ERROR: 30001 doSomething is unexpected error *main.MyError
おわり
errorの扱いについてサラっとまとめました。
あまり長いと書くのも読むのも疲れるのでエラーハンドリングについては別記事でかきます\(^o^)/