ダメなケース
同じメッセージを持つ、別々のエラーは等しくない。
err1 := errors.New("user not found")
err2 := errors.New("user not found")
fmt.Println(err1 == err2) //=> false
なので、こういったコードはうまくいかない。
package user
func Lookup() (*User, error) {
return nil, errors.New("user not found")
}
package main
func main() {
user, err := user.Lookup()
if err == errors.New("user not found") {
fmt.Fprintln(os.Stderr, "failed to lookup user")
}
}
シンプルなエラーの判別
エラーを比較するには、エラーを生成するコードとエラーを判別するコードの間でエラーを共有する。
package user
var ErrNotFound = errors.New("user not found")
func Lookup() (*User, error) {
return nil, ErrNotFound
}
package main
func main() {
user, err := user.Lookup()
if err == user.ErrNotFound {
fmt.Fprintln(os.Stderr, "failed to lookup user")
}
}
データをもつエラーの判別
データをもつエラーを表現するには、Error()
を実装する型を定義する。errors.As()
を使うと、エラーの判別をしつつ型アサーションにより内部のデータにアクセスできる。
package user
type ErrNotFound struct {
ID int
}
func (err ErrNotFound) Error() string {
return fmt.Sprintf("user not found: %d", err.ID)
}
func Lookup(id int) (*User, error) {
return nil, ErrorNotFound{ID: id}
}
package main
func main() {
user, err := user.Lookup(1)
var notFoundErr user.ErrNotFound
if errors.As(err, ¬FoundErr) {
fmt.Fprintf(os.Stderr, "failed to lookup user ID:%d\n", notFoundErr.ID)
}
}