errors.As によるアンラップ
CoddyのGOジャーニー「論理とフロー」セクションの一部 — レッスン 41/68。
errors.Is はエラーチェーン内の特定のエラー値を識別するのに役立ちますが、カスタムエラータイプの実際のフィールドやデータにアクセスする必要がある場合もあります。errors.As 関数は、チェーン内で特定の型に一致する最初のエラーを見つけ、検査のためにそれを抽出することで、この機能を提供します。
errors.As 関数は、調査対象のエラーと、ターゲットとなるエラー型の変数へのポインタという2つのパラメータを受け取ります。チェーン内に一致するエラー型が見つかった場合、その変数にそのエラーを代入し、true を返します。
var validationErr ValidationError
if errors.As(wrappedErr, &validationErr) {
fmt.Printf("Field: %s, Message: %s\n", validationErr.Field, validationErr.Message)
}これは、追加のコンテキストを含むカスタムエラー型を扱う場合に特に強力です。等価性のみをチェックする errors.Is とは異なり、errors.As は実際のエラーインスタンスを抽出するため、そのフィールドやメソッドにアクセスできるようになります。これにより、複雑なアプリケーションにおけるエラーハンドリングがより洗練され、情報量の多いものになります。
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
チャレンジ
簡単errors.As を使用して、ラップされたエラーチェーンからカスタムエラー型を抽出および調査する API エラー処理システムを構築します。このチャレンジでは、追加のコンテキストでラップされている場合でも、errors.As を使用して特定のカスタムエラー型のフィールドやデータにアクセスする方法を学びます。
2つの入力を受け取ります:
"endpoint,method,error_code,error_field"形式の API リクエストの詳細を含む文字列(例:"/users,POST,400,email")"service_name,request_id"形式のシステムコンテキストを含む文字列(例:"UserAPI,req_12345")
あなたのタスクは以下の通りです:
- 3つのフィールドを持つ
APIError構造体というカスタムエラー型を作成します:Code(int) - HTTP ステータスコードField(string) - エラーの原因となったフィールドMessage(string) - エラーの説明
"API error [code]: [message] (field: [field])"を返すAPIErrorのError() stringメソッドを実装します。- 最初の入力をカンマで分割して、エンドポイント、メソッド、エラーコード、エラーフィールドを取得します。
- 2番目の入力をカンマで分割して、サービス名とリクエスト ID を取得します。
- エラーコードの文字列を整数に変換します。
- エラーコードに基づいて
APIErrorインスタンスを作成します:- コードが 400 の場合:メッセージ
"invalid request data" - コードが 401 の場合:メッセージ
"authentication required" - コードが 404 の場合:メッセージ
"resource not found" - コードが 500 の場合:メッセージ
"internal server error" - その他のコードの場合:メッセージ
"unknown error"
- コードが 400 の場合:メッセージ
fmt.Errorfと%wを使用して、エンドポイントレベルのラップされたエラーを作成します:"[method] [endpoint] failed: %w"- サービスレベルのラップされたエラーを作成します:
"[service_name] request [request_id] failed: %w" errors.Asを使用してラップされたエラーチェーンからAPIErrorを抽出し、抽出結果を表示します:- 抽出に成功した場合:
"API error extracted successfully" - 抽出に失敗した場合:
"Failed to extract API error"
- 抽出に成功した場合:
- 抽出に成功した場合は、抽出されたエラーの詳細を表示します:
"Extracted Error Details:""Code: [code]""Field: [field]""Message: [message]""Full error: [full_error_message_from_Error_method]"
- 完全なエラーチェーンを表示します:
"Error Chain:""Original: [original_api_error_message]""Endpoint level: [endpoint_level_error_message]""Service level: [service_level_error_message]"
- 最終的な分析を表示します:
"Error Analysis:""Service: [service_name]""Request ID: [request_id]""Endpoint: [method] [endpoint]""HTTP Status: [code]""Problem Field: [field]""Error Category: [error_category]"(error_categoryは、コード 400-499 の場合は"Client Error"、コード 500-599 の場合は"Server Error"、その他のコードの場合は"Unknown"とします)
strings パッケージを使用して入力文字列をカンマで分割し、strconv パッケージを使用してエラーコード文字列を整数に変換し、errors パッケージを errors.As に、fmt パッケージをエラーのラッピングに使用します。このチャレンジでは、errors.As を使用してラップされたエラーチェーン内のカスタムエラー型の特定のフィールドやメソッドにアクセスし、高度なエラー処理と分析を可能にする方法を示します。
チートシート
errors.As 関数は、エラーチェーンから特定のエラー型を抽出し、カスタムエラーのフィールドやメソッドへのアクセスを可能にします。
errors.As は、調査対象のエラーと、ターゲットとなるエラー型の変数へのポインタという2つのパラメータを受け取ります。
var validationErr ValidationError
if errors.As(wrappedErr, &validationErr) {
fmt.Printf("Field: %s, Message: %s\n", validationErr.Field, validationErr.Message)
}同等性のみをチェックする errors.Is とは異なり、errors.As は実際のエラーインスタンスを抽出するため、そのフィールドやメソッドにアクセスして、より高度なエラーハンドリングを行うことができます。
自分で試してみよう
package main
import (
"errors"
"fmt"
"strconv"
"strings"
)
func main() {
// 入力を読み込む
var apiDetails string
var systemContext string
fmt.Scanln(&apiDetails)
fmt.Scanln(&systemContext)
// 入力を解析する
apiParts := strings.Split(apiDetails, ",")
endpoint := apiParts[0]
method := apiParts[1]
errorCodeStr := apiParts[2]
errorField := apiParts[3]
contextParts := strings.Split(systemContext, ",")
serviceName := contextParts[0]
requestID := contextParts[1]
// エラーコードを整数に変換する
errorCode, _ := strconv.Atoi(errorCodeStr)
// TODO: 以下にコードを記述してください
// 1. Code、Field、Messageフィールドを持つAPIError構造体を作成する
// 2. APIErrorのError()メソッドを実装する
// 3. エラーコードに基づいてAPIErrorインスタンスを作成する
// 4. ラップされたエラー(エンドポイントレベルおよびサービスレベル)を作成する
// 5. errors.Asを使用して、ラップされたエラーチェーンからAPIErrorを抽出する
// 6. 抽出結果とエラーの詳細を表示する
// 7. エラーチェーンと最終的な分析を表示する
}このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
論理とフローのすべてのレッスン
7エラーハンドリング詳説
カスタムエラー型%w によるエラーのラッピングerrors.Is によるアンラップerrors.As によるアンラップpanic の理解recover の使用まとめ:安全な除算