カスタムエラーの作成
errors.New、fmt.Errorf、センチネルエラー
「カスタムエラーの作成」はCoddyKit上の無料Go Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGo Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Go Academyコースには全4レッスンが含まれています。
カスタムエラー型を使う理由
カスタムエラー型は、文字列メッセージ以外の構造化データを保持できます。これにより、呼び出し側は特定のエラー条件を調べ、それに応じて処理できます:
package main
import "fmt"
// Custom error type carries extra context
type HTTPError struct {
StatusCode int
Message string
}
func (e *HTTPError) Error() string {
return fmt.Sprintf("HTTP %d: %s", e.StatusCode, e.Message)
}
func fetch(url string) error {
return &HTTPError{404, "page not found"}
}
func main() {
err := fetch("http://example.com")
fmt.Println(err) // HTTP 404: page not found
}error インターフェースの実装
Error() string メソッドを持つ任意の型は、error を満たします:
package main
import "fmt"
type ValidationError struct {
Field string
Value interface{}
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation: field %q value %v — %s", e.Field, e.Value, e.Message)
}
func validateAge(age int) error {
if age < 0 || age > 150 {
return &ValidationError{"age", age, "must be between 0 and 150"}
}
return nil
}
func main() {
fmt.Println(validateAge(-5))
}errors.New によるセンチネルエラー
センチネルエラーは、よく知られたエラー条件を表すパッケージレベルの変数です:
package main
import ("fmt"; "errors")
var (
ErrNotFound = errors.New("not found")
ErrUnauthorized = errors.New("unauthorized")
ErrAlreadyExists = errors.New("already exists")
)
func getUser(id int) (string, error) {
if id != 1 { return "", ErrNotFound }
return "Alice", nil
}
func main() {
_, err := getUser(99)
if errors.Is(err, ErrNotFound) {
fmt.Println("user does not exist")
}
}ラップに %w を使う fmt.Errorf
%w を指定した fmt.Errorf はエラーをラップし、元のエラーを保持するため、errors.Is と errors.As で調べられます:
package main
import ("fmt"; "errors")
var ErrDatabase = errors.New("database error")
func queryDB() error {
return fmt.Errorf("queryDB: %w", ErrDatabase)
}
func main() {
err := queryDB()
fmt.Println(err) // queryDB: database error
fmt.Println(errors.Is(err, ErrDatabase)) // true — unwrapped
}Unwrap を持つカスタムエラー
カスタムエラー型に Unwrap() error を実装すると、エラーチェーンに参加できるようになります:
package main
import ("fmt"; "errors")
var ErrNotFound = errors.New("not found")
type QueryError struct {
Query string
Err error
}
func (e *QueryError) Error() string {
return fmt.Sprintf("query %q: %v", e.Query, e.Err)
}
func (e *QueryError) Unwrap() error { return e.Err }
func main() {
err := &QueryError{"SELECT *", ErrNotFound}
fmt.Println(err)
fmt.Println(errors.Is(err, ErrNotFound)) // true
}errors.Is — 同一性チェック
errors.Is はエラーチェーンをたどり、ターゲットと等しいエラーを探します:
package main
import ("fmt"; "errors")
var ErrTimeout = errors.New("timeout")
func deepCall() error {
return fmt.Errorf("layer3: %w", fmt.Errorf("layer2: %w", ErrTimeout))
}
func main() {
err := deepCall()
fmt.Println(errors.Is(err, ErrTimeout)) // true — found deep in chain
}errors.As — 型の取り出し
errors.As はエラーチェーン内でターゲット型に一致する最初のエラーを見つけ、それを代入します:
package main
import ("fmt"; "errors")
type PermissionError struct{ User string }
func (e *PermissionError) Error() string { return "permission denied for " + e.User }
func action(user string) error {
return fmt.Errorf("action: %w", &PermissionError{user})
}
func main() {
err := action("bob")
var pe *PermissionError
if errors.As(err, &pe) {
fmt.Println("denied:", pe.User) // denied: bob
}
}複数エラーのラップ(Go 1.20 以降)
Go 1.20 で、エラーを結合する errors.Join と、複数の %w を指定できる fmt.Errorf が追加されました:
package main
import ("fmt"; "errors")
func validate(name, email string) error {
var errs []error
if name == "" { errs = append(errs, errors.New("name required")) }
if email == "" { errs = append(errs, errors.New("email required")) }
return errors.Join(errs...)
}
func main() {
err := validate("", "")
fmt.Println(err)
// name required
// email required
}エラー型の命名規則
Go におけるエラー変数と型の命名規則:
- センチネルエラー変数:
ErrXxx(例:ErrNotFound) - カスタムエラー型:
XxxError(例:ValidationError) - センチネルエラーにはパッケージレベルの var を、詳細なエラーにはポインター型を使用します
- 呼び出し側が
errors.Is/errors.Asで使用できるようにエクスポートします
それぞれの方法を使う場面
適切なエラー処理方法の選択:
errors.New— 追加データが不要で、センチネルの同一性をチェックする単純なエラーfmt.Errorf— 必要に応じてラップできる、書式付きメッセージ- カスタム型 — 呼び出し側が構造化データ(フィールドやコード)を必要とする場合
errors.Join— 複数のバリデーションエラーをまとめる場合
確認問題
エラーチェーンから特定のエラー型を取り出せる関数はどれですか?
まとめ:カスタムエラー
まとめ:
Error() stringを実装してカスタムエラー型を作成しますUnwrap() errorを追加してエラーチェーンに参加させます- 同一性のチェックには
errors.Is、型の取り出しにはerrors.Asを使用します - センチネルエラーは
ErrXxx、カスタム型はXxxErrorとします errors.Joinは複数のエラーをまとめます(Go 1.20 以降)
よくある質問
「カスタムエラーの作成」レッスンは無料ですか?
はい。「カスタムエラーの作成」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Go Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Go Academyコースには全4レッスンが含まれています。
「カスタムエラーの作成」で何を学びますか?
errors.New、fmt.Errorf、センチネルエラー ブラウザで直接実行するハンズオンコードでGo Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Go Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのGo Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「カスタムエラーの作成」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このGo Academyレッスンでコードを書いて実行できますか?
はい。すべてのGo Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。