%w によるエラーのラッピング
CoddyのGOジャーニー「論理とフロー」セクションの一部 — レッスン 39/68。
アプリケーションでエラーが発生した際、コードの異なるレイヤーをさかのぼるにつれて、追加のコンテキストが必要になることがよくあります。Goは、fmt.Errorf で %w フォーマット動詞を使用したエラーラッピングを通じて、これを行うための強力なメカニズムを提供しています。
エラーラッピングを使用すると、元のエラーを保持したまま、既存のエラーにコンテキスト情報を追加できます。これにより、何が問題だったのかという完全な履歴を保持するエラーチェーンが作成されます:
originalErr := errors.New("file not found")
wrappedErr := fmt.Errorf("failed to load config: %w", originalErr)%w 動詞は特殊です。これは fmt.Errorf に対し、エラーを単に文字列に変換するのではなく、ラップするように指示します。これにより元のエラーが保持されるため、後で errors.Is や errors.As といった関数を使用して検証することができます。
このパターンは、エラーが複数の関数を通過し、それぞれが独自のコンテキストを追加するような大規模なアプリケーションにおいて特に価値があります。例えば、データベース接続エラーが "failed to connect to database" でラップされ、さらに "unable to start server" でラップされることで、何がどこで起こったのかという明確な形跡を作成できます。
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
チャレンジ
簡単アプリケーションのさまざまなレイヤーを伝播する際に、コンテキスト情報を付加してエラーをラップするファイル処理システムを構築します。このチャレンジでは、fmt.Errorf で %w フォーマット動詞を使用して、元のエラーを保持しながら意味のあるコンテキストを追加するエラーチェーンを作成する方法を学びます。
2つの入力を受け取ります:
"filename,operation,status"形式のファイル操作の詳細を含む文字列(例:"config.json,read,permission_denied")"service_name,component"形式のシステムコンテキストを含む文字列(例:"UserService,ConfigLoader")
あなたのタスクは以下の通りです:
- 最初の入力をカンマで分割して、filename、operation、status を取得します。
- 2番目の入力をカンマで分割して、service name と component を取得します。
- status に基づいて
errors.New()を使用し、元のエラーを作成します:- status が
"permission_denied"の場合:"permission denied" - status が
"not_found"の場合:"file not found" - status が
"corrupted"の場合:"file corrupted" - それ以外の status の場合:
"unknown error"
- status が
fmt.Errorfと%wを使用して、ファイルレベルのラップされたエラーを作成します:"failed to [operation] file [filename]: %w"- コンポーネントレベルのラップされたエラーを作成します:
"[component] error: %w" - サービスレベルのラップされたエラーを作成します:
"[service_name] operation failed: %w" - 各レベルを出力してエラーチェーンを表示します:
"Original error: [original_error_message]""File level: [file_level_error_message]""Component level: [component_level_error_message]""Service level: [service_level_error_message]"
- エラーチェーンのサマリーを表示します:
"Error Chain Summary:""File: [filename]""Operation: [operation]""Component: [component]""Service: [service_name]""Root cause: [original_error_message]"
入力文字列をカンマで分割するには strings パッケージを、元のエラーを作成するには errors パッケージを、ラップされたエラーを作成するには fmt パッケージを使用してください。このチャレンジは、%w によるエラーラッピングが、エラーがアプリケーションの異なるレイヤーを移動する際にどのように明確なコンテキストの痕跡を作成し、デバッグをより効果的にするかを示しています。
チートシート
エラーラッピングを使用すると、元のエラーを保持したまま、既存のエラーにコンテキスト情報を追加できます。fmt.Errorf で %w フォーマット動詞を使用します。
originalErr := errors.New("file not found")
wrappedErr := fmt.Errorf("failed to load config: %w", originalErr)%w 動詞は元のエラーを保持するため、後で errors.Is や errors.As といった関数を使用して調査することができます。これにより、何が問題だったかの全履歴を維持するエラーチェーンが作成されます。これは、大規模なアプリケーションでエラーが複数の関数を通過する場合に非常に有用です。
自分で試してみよう
package main
import (
"errors"
"fmt"
"strings"
)
func main() {
// 入力を読み込む
var fileDetails string
var systemContext string
fmt.Scanln(&fileDetails)
fmt.Scanln(&systemContext)
// 入力を解析する
fileInfo := strings.Split(fileDetails, ",")
filename := fileInfo[0]
operation := fileInfo[1]
status := fileInfo[2]
contextInfo := strings.Split(systemContext, ",")
serviceName := contextInfo[0]
component := contextInfo[1]
// TODO: 以下にコードを記述してください
// ステータスに基づいて元のエラーを作成する
// ファイルレベルのラップされたエラーを作成する
// コンポーネントレベルのラップされたエラーを作成する
// サービスレベルのラップされたエラーを作成する
// 各エラーレベルとサマリーを出力する
}このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
論理とフローのすべてのレッスン
7エラーハンドリング詳説
カスタムエラー型%w によるエラーのラッピングerrors.Is によるアンラップerrors.As によるアンラップpanic の理解recover の使用まとめ:安全な除算