Go練習問題4-03:カスタムエラーを理解しよう

記事内に商品プロモーションを含む場合があります

Go言語の初心者向け問題4-03:カスタムエラーを理解しよう

この問題を解くために必要な知識:
レベル1~3の知識メモリ管理の基本エラーハンドリングとカスタムエラーチャネルの選択タイムアウト処理パッケージinit関数ファイル操作エンコーディングとデコーディングテストの書き方ベンチマークテストドキュメントの生成

<<前の問題 問題集Top 次の問題>>

Go言語の文法「カスタムエラー」とは





ここではカスタムエラーの意味や使い方を復習します。必要ない方はここをクリックして練習問題へ飛びましょう。

Go言語では、エラーハンドリングが非常に重要な役割を果たしますが、その中でもカスタムエラーの作成は、特に複雑なシステムやアプリケーションを開発する際に役立つ強力な機能です。

カスタムエラーとは?

カスタムエラーとは、Goの組み込みのerror型ではカバーしきれない、特定のエラーメッセージや追加の情報を持たせたエラーを定義することです。これにより、より細かいエラー処理が可能になります。

カスタムエラーを作成する理由

カスタムエラーを作成することで、次のような利点があります。

  • 明確なエラーメッセージ: 特定の状況に応じた詳細なエラーメッセージを提供できます。
  • 追加の情報: エラーに関連する追加の情報(例えば、エラーが発生した場所や条件)を持たせることができます。
  • 型安全性: エラーの種類に基づいて分岐処理を行う際に、型アサーションを使って安全に処理を分けられます。

カスタムエラーの作成方法

カスタムエラーを作成するためには、まずerrorインターフェースを実装した構造体を定義します。この構造体にエラーに関する追加情報を持たせることができます。

以下は、カスタムエラーの基本的な作成例です。

package main

import (
    "fmt"
)

// MyErrorは、カスタムエラーを定義するための構造体です。
type MyError struct {
    Code    int
    Message string
}

// Errorメソッドは、MyErrorがerrorインターフェースを実装するために必要です。
func (e *MyError) Error() string {
    return fmt.Sprintf("エラー %d: %s", e.Code, e.Message)
}

// 何らかのエラーが発生する関数の例
func doSomething() error {
    // カスタムエラーを返します
    return &MyError{
        Code:    404,
        Message: "リソースが見つかりません",
    }
}

func main() {
    err := doSomething()
    if err != nil {
        // エラーを型アサーションで検査し、カスタムエラーに応じた処理を行います
        if myErr, ok := err.(*MyError); ok {
            fmt.Println("カスタムエラーが発生:", myErr)
        } else {
            fmt.Println("エラーが発生:", err)
        }
    }
}

カスタムエラーの詳細解説

  1. 構造体の定義
    MyErrorという構造体を定義し、その中にエラーに関する情報(例えば、エラーコードやメッセージ)を格納します。
  2. Errorメソッドの実装
    errorインターフェースを実装するために、Error()メソッドを定義します。このメソッドは、エラーメッセージを文字列として返します。
  3. カスタムエラーの返却
    doSomething関数では、処理の中でエラーが発生した場合に、MyError型のカスタムエラーを返します。
  4. エラーの処理
    main関数では、doSomething関数から返されたエラーを受け取り、型アサーションを使ってカスタムエラーかどうかを確認します。カスタムエラーの場合には、エラーの詳細情報を出力できます。

カスタムエラーを使うべき状況

カスタムエラーは、以下のような状況で特に有効です。

  • 特定のエラー状況を詳細に管理したい場合
  • エラーに関連する追加情報(エラーコードや発生場所など)を持たせたい場合
  • エラーの種類によって処理を分岐させたい場合

カスタムエラーは、エラー処理をより柔軟かつ強力にするための重要なツールです。これを活用することで、Goプログラムの信頼性と保守性が向上します。

カスタムエラーをしっかり理解して、実際のプロジェクトで役立てましょう。

Go練習問題4-3:年齢検証プログラムを作成しよう

カスタムエラーを作成し、それを用いた年齢検証プログラムを作成しましょう。

ユーザーが入力した年齢が20歳未満の場合に、カスタムエラーを発生させ、そのエラーメッセージを表示するプログラムです。

年齢が20歳以上であれば「年齢が有効です」というメッセージを表示します。

この問題の要件

以下の要件に従ってコードを完成させてください。

  • CustomErrorという名前のカスタムエラー型を作成し、エラーコードとメッセージを持たせること。
  • Error()メソッドを実装して、カスタムエラーがerrorインターフェースを実装するようにすること。
  • validateAge()関数を定義し、引数として年齢を受け取ること。
  • validateAge()関数内で、年齢が20歳未満の場合に、エラーコード1001と「年齢が20歳未満です」というメッセージを持つCustomErrorを返すこと。
  • main()関数で年齢を変数に格納し、validateAge()関数を呼び出して年齢を検証すること。
  • validateAge()関数から返されたエラーがカスタムエラーかどうかを型アサーションで確認し、エラーメッセージを表示すること。
  • 年齢が20歳以上の場合は「年齢が有効です」と表示すること。

ただし、以下のような実行結果となるコードを書くこと。

*****↓↓正解コードの実行結果の例↓↓*****

カスタムエラーが発生: エラーコード 1001: 年齢が20歳未満です

この問題を解くヒント

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

ヒント1【コードの構成を見る】

正解のコードは上から順に以下のような構成となっています。

1.import文
 1-1. errorsパッケージのインポート
 1-2. fmtパッケージのインポート

2.CustomError構造体の定義
 2-1. カスタムエラーを定義するための構造体CustomErrorを宣言
 2-2. Codeフィールド(エラーコード)とMessageフィールド(エラーメッセージ)の宣言

3.Errorメソッドの定義
 3-1. CustomError構造体にError()メソッドを定義
 3-2. エラーコードとメッセージを含むフォーマットされた文字列を返す

4.validateAge関数の定義
 4-1. validateAge関数を定義し、引数として年齢を受け取る
 4-2. 年齢が20未満の場合、CustomError型のエラーを生成し、返す
 4-3. 年齢が20以上の場合は、nilを返す

5.main関数の定義
 5-1. 年齢を変数ageに格納
 5-2. validateAge関数を呼び出し、年齢を検証
  5-2-1. エラーが発生した場合の処理を行う
   5-2-1-1. 型アサーションを使用して、エラーがCustomError型かどうかを確認
   5-2-1-2. カスタムエラーの場合は、そのエラーメッセージを表示
   5-2-1-3. それ以外のエラーの場合は、一般的なエラーメッセージを表示
 5-3. 年齢が有効であれば、「年齢が有効です」というメッセージを表示

ヒント2【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

package main

import (
    "errors"
    "fmt"
)

// CustomErrorはカスタムエラーを定義するための構造体です。
type CustomError struct {
    Code    int
    Message string
}

// Errorメソッドは、CustomErrorがerrorインターフェースを実装するために必要です。
/*【穴埋め問題1】
ここにErrorメソッドを定義し、エラーコードとメッセージを含むフォーマットされた文字列を返すコードを書いてください。
*/

func validateAge(age int) error {
    if age < 20 {
        // カスタムエラーを返す
        return &CustomError{
            Code:    1001,
            Message: "年齢が20歳未満です",
        }
    }
    return nil
}

func main() {
    age := 18

    // validateAge関数を呼び出して年齢を検証します
    err := validateAge(age)
    if err != nil {
        /*【穴埋め問題2】
        ここに型アサーションを使ってエラーがCustomError型かどうかを確認し、適切なエラーメッセージを表示するコードを書いてください。
        */
        return
    }

    // 年齢が有効な場合の処理
    fmt.Println("年齢が有効です:", age)
}

 

このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。

解答例と解説

この問題の一つの正解例とそのコードの解説を以下に示します。

正解コードの例

例えば以下のようなプログラムが考えられます。

package main

import (
    "errors"
    "fmt"
)

// CustomErrorはカスタムエラーを定義するための構造体です。
type CustomError struct {
    Code    int
    Message string
}

// Errorメソッドは、CustomErrorがerrorインターフェースを実装するために必要です。
func (e *CustomError) Error() string {
    return fmt.Sprintf("エラーコード %d: %s", e.Code, e.Message)
}

// validateAgeは年齢を検証する関数です。年齢が20未満の場合、カスタムエラーを返します。
func validateAge(age int) error {
    if age < 20 {
        // カスタムエラーを返す
        return &CustomError{
            Code:    1001,
            Message: "年齢が20歳未満です",
        }
    }
    return nil
}

func main() {
    age := 18

    // validateAge関数を呼び出して年齢を検証します
    err := validateAge(age)
    if err != nil {
        // 型アサーションを使ってカスタムエラーかどうかを確認します
        if customErr, ok := err.(*CustomError); ok {
            fmt.Println("カスタムエラーが発生:", customErr)
        } else {
            fmt.Println("エラーが発生:", err)
        }
        return
    }

    // 年齢が有効な場合の処理
    fmt.Println("年齢が有効です:", age)
}

正解コードの解説

パッケージのインポート

import (
    "errors"
    "fmt"
)

最初に、Goの標準ライブラリからerrorsfmtパッケージをインポートしています。

errorsパッケージは、エラーメッセージを作成するために使用され、fmtパッケージはフォーマットされた出力を行うために使用されます。

カスタムエラーを定義する構造体の作成

type CustomError struct {
    Code    int
    Message string
}

CustomErrorという名前の構造体を作成しています。この構造体は、エラーコードを格納するCodeと、エラーメッセージを格納するMessageという2つのフィールドを持っています。

これにより、標準のエラーメッセージに加えて、カスタム情報をエラーに持たせることができます。

カスタムエラーの文字列表現を定義するメソッド

func (e *CustomError) Error() string {
    return fmt.Sprintf("エラーコード %d: %s", e.Code, e.Message)
}

Errorメソッドは、CustomError構造体がerrorインターフェースを実装するために必要なメソッドです。

このメソッドは、fmt.Sprintfを使って、エラーコードとエラーメッセージをフォーマットし、文字列として返します。

これにより、エラーが発生したときに、カスタムエラーメッセージを表示することができます。

年齢を検証する関数

func validateAge(age int) error {
    if age < 20 {
        return &CustomError{
            Code:    1001,
            Message: "年齢が20歳未満です",
        }
    }
    return nil
}

validateAge関数は、引数として年齢を受け取り、その年齢が20歳未満である場合にCustomErrorを返します。

年齢が有効であれば、nilを返します。これにより、関数がエラーを返すかどうかで、次の処理を判断できます。

メイン関数

func main() {
    age := 18

    err := validateAge(age)
    if err != nil {
        if customErr, ok := err.(*CustomError); ok {
            fmt.Println("カスタムエラーが発生:", customErr)
        } else {
            fmt.Println("エラーが発生:", err)
        }
        return
    }

    fmt.Println("年齢が有効です:", age)
}

main関数は、プログラムのエントリーポイントです。まず、年齢を表す変数ageを18に設定します。次に、validateAge関数を呼び出して年齢を検証します。

エラーハンドリングとカスタムエラーの確認

関数がエラーを返した場合、そのエラーがCustomError型かどうかを型アサーションを使って確認します。

CustomErrorであれば、そのカスタムエラーの内容を表示し、それ以外のエラーであれば一般的なエラーメッセージを表示します。エラーが発生しなければ、年齢が有効である旨を表示します。

<<前の問題 問題集Top 次の問題>>

この問題への質問・コメント

この問題を作成するにあたりAIを活用しています。

問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。






    Go練習問題集へ戻る
    トップページへ戻る