Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 19353] ファイルの概要

このコミットは、Go言語の公式ドキュメントである doc/effective_go.html の「Errors」セクションに対する修正です。具体的には、エラーハンドリングのベストプラクティスについて、より明確な説明を追加し、エラー発生時に nil ポインタを返すだけでなく、具体的な error 値も返すことの重要性を強調しています。

コミット

doc/effective_go.html: エラーについてもう少し詳しく

エラーがどのように使われるか、特にエラー時に nil ポインタを返すだけでは不十分であり、問題を示すエラー値も返す必要があることを、もう少し明確にする。

Fixes #1963.

LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/97360045

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/1476686cdb6acafdf62aad7672c3839bc4ca7033

元コミット内容

commit 1476686cdb6acafdf62aad7672c3839bc4ca7033
Author: Rob Pike <r@golang.org>
Date:   Wed May 14 13:46:58 2014 -0700

    doc/effective_go.html: a little more about errors
    Make it a little clearer how they are used, in particular that
    it is not enough just to return a nil pointer on error, but also
    to return an error value explaining the problem.
    
    Fixes #1963.
    
    LGTM=bradfitz
    R=golang-codereviews, bradfitz
    CC=golang-codereviews
    https://golang.org/cl/97360045

変更の背景

この変更の背景には、Go言語におけるエラーハンドリングの慣習をより明確にし、開発者がより堅牢で情報量の多いエラー処理を実装できるようにするという目的があります。Go言語では、関数が複数の戻り値を返すことができ、この機能はエラーハンドリングに広く利用されています。慣習として、エラーが発生する可能性のある関数は、最後の戻り値として error 型の値を返します。エラーがない場合は nil を返し、エラーがある場合は nil ではない error 値を返します。

しかし、初期のGo開発者の中には、エラーが発生した場合にポインタ型の戻り値(例えば *os.File)を nil に設定するだけで、error 値自体は無視してしまう、あるいは適切に設定しないという誤解や慣習があった可能性があります。これは、呼び出し元がエラーの原因や詳細を特定できず、デバッグや適切なエラー回復が困難になるという問題を引き起こします。

このコミットは、effective_go.html というGo言語の「効果的なGoプログラミング」に関する公式ガイドを修正することで、この誤解を解消し、エラー発生時には必ず具体的な error 値を返すというGoの慣習を強調することを目的としています。特に、os.Open のような標準ライブラリの関数が、成功時には *os.Filenil を返し、失敗時には nil と具体的な os.PathError を返すという挙動を例に挙げることで、このベストプラクティスを明確に示しています。

Fixes #1963 という記述から、この変更がGoのIssueトラッカーで報告された特定の課題(Issue 1963)を解決するために行われたことがわかります。このIssueは、おそらく effective_go.html のエラーに関する説明が不十分である、または誤解を招く可能性があるという指摘だったと推測されます。

前提知識の解説

このコミットを理解するためには、以下のGo言語の基本的な概念と慣習を理解しておく必要があります。

  1. 多値戻り (Multiple Return Values): Go言語の関数は、複数の値を返すことができます。これは、エラーハンドリングにおいて非常に重要な機能です。例えば、value, err := someFunction() のように、通常の戻り値とエラー値を同時に受け取ることができます。

  2. error インターフェース: Go言語には、エラーを表すための組み込みインターフェース error があります。

    type error interface {
        Error() string
    }
    

    このインターフェースは、Error() string メソッドを一つだけ持ちます。このメソッドは、エラーの人間が読める形式の文字列表現を返します。Goの標準ライブラリやユーザー定義のエラー型は、このインターフェースを実装することで、エラーとして扱われます。

  3. nil とエラーハンドリング: Goの慣習では、関数が正常に実行された場合、error 型の戻り値は nil になります。nil は、ポインタ、インターフェース、マップ、スライス、チャネル、関数などのゼロ値であり、「値がない」ことを意味します。エラーが発生した場合、error 型の戻り値は nil ではない具体的なエラーオブジェクトになります。 一般的なエラーチェックのパターンは以下のようになります。

    result, err := someFunction()
    if err != nil {
        // エラー処理
        fmt.Println("Error:", err)
        return
    }
    // 正常処理
    fmt.Println("Result:", result)
    
  4. os.Open の挙動: os.Open は、ファイルを開くためのGoの標準ライブラリ関数です。そのシグネチャは以下のようになっています。

    func Open(name string) (*File, error)
    

    この関数は、成功すると *os.File 型のファイルディスクリプタと nil エラーを返します。ファイルが見つからない、アクセス権がないなどの理由で失敗すると、nil*os.File と、具体的な error 型の値(例えば *os.PathError)を返します。

  5. os.PathError: os.PathError は、ファイルパスに関連する操作(オープン、読み取り、書き込みなど)で発生したエラーを詳細に記述するための構造体です。これは error インターフェースを実装しています。

    // PathError records an error and the operation and
    // file path that caused it.
    type PathError struct {
        Op   string // operation leading to the error
        Path string // the file path
        Err  error  // the raw error
    }
    
    func (e *PathError) Error() string {
        return e.Op + " " + e.Path + ": " + e.Err.Error()
    }
    

    os.PathError は、どの操作 (Op) が、どのパス (Path) で、どのような根本的なエラー (Err) を引き起こしたかを明確に示します。

技術的詳細

このコミットは、Go言語のドキュメント effective_go.html の内容を修正することで、Goのエラーハンドリングのベストプラクティスを強化しています。技術的な変更点は、コードの挙動そのものではなく、その説明の仕方と強調点にあります。

変更前は、エラーハンドリングについて「Goの多値戻りによって、通常の戻り値と並行して詳細なエラー記述を返すことが容易になる」と述べていました。しかし、この記述だけでは、エラー時に nil ポインタを返すだけで十分であるという誤解を生む可能性がありました。

変更後では、以下の点が明確に強調されています。

  1. 「詳細なエラー情報を提供するためにこの機能(多値戻り)を使用することは良いスタイルである」 という文言が追加されました。これにより、単にエラーを検出するだけでなく、その詳細を伝えることの重要性が強調されます。
  2. os.Open の例がより詳細に説明されました。変更前は「os.Openos.PathError を返す」とだけ書かれていましたが、変更後では os.Open は失敗時に nil ポインタを返すだけでなく、何が問題だったかを説明するエラー値も返す」 と明記されています。
  3. さらに、os.Open が通常の *os.File 戻り値と並行してエラー値を返すこと、そして 「ファイルが正常に開かれた場合、エラーは nil になるが、問題がある場合は os.PathError を保持する」 という具体的な挙動が追加されました。

これらの変更は、Goのエラーハンドリングの哲学である「エラーは明示的に処理されるべきであり、その詳細が呼び出し元に伝達されるべきである」という原則を、ドキュメントを通じてより強力に推進するものです。これにより、開発者はエラーが発生した際に、単に「何か問題が起きた」と知るだけでなく、「何が、どこで、どのように問題が起きたのか」を理解し、適切な対応を取ることができるようになります。

このドキュメントの修正は、Go言語の設計思想、特にエラーハンドリングにおける透明性と堅牢性を反映しており、Goプログラミングの品質向上に寄与するものです。

コアとなるコードの変更箇所

変更は doc/effective_go.html ファイルのみです。

--- a/doc/effective_go.html
+++ b/doc/effective_go.html
@@ -3287,9 +3287,18 @@ the garbage collector for bookkeeping.
 
 <p>
 Library routines must often return some sort of error indication to
-the caller.  As mentioned earlier, Go's multivalue return makes it
+the caller.
+As mentioned earlier, Go's multivalue return makes it
 easy to return a detailed error description alongside the normal
-return value.  By convention, errors have type <code>error</code>,
+return value.
+It is good style to use this feature to provide detailed error information.
+For example, as we'll see, <code>os.Open</code> doesn't
+just return a <code>nil</code> pointer on failure, it also returns an
+error value that describes what went wrong.
+</p>
+
+<p>
+By convention, errors have type <code>error</code>,
 a simple built-in interface.
 </p>
 <pre>
@@ -3301,7 +3310,12 @@ type error interface {
 A library writer is free to implement this interface with a
 richer model under the covers, making it possible not only
 to see the error but also to provide some context.
-For example, <code>os.Open</code> returns an <code>os.PathError</code>.
+As mentioned, alongside the usual <code>*os.File</code>
+return value, <code>os.Open</code> also returns an
+error value.
+If the file is opened successfully, the error will be <code>nil</code>,
+but when there is a problem, it will hold an
+<code>os.PathError</code>:
 </p>
 <pre>
 // PathError records an error and the operation and

コアとなるコードの解説

このコミットは、Go言語のドキュメント effective_go.html の特定の部分にテキストを追加・修正しています。

変更点1:

-the caller.  As mentioned earlier, Go's multivalue return makes it
+the caller.
+As mentioned earlier, Go's multivalue return makes it
 easy to return a detailed error description alongside the normal
-return value.  By convention, errors have type <code>error</code>,
+return value.
+It is good style to use this feature to provide detailed error information.
+For example, as we'll see, <code>os.Open</code> doesn't
+just return a <code>nil</code> pointer on failure, it also returns an
+error value that describes what went wrong.
+</p>
+
+<p>
+By convention, errors have type <code>error</code>,
  • 変更前: 「Goの多値戻りによって、通常の戻り値と並行して詳細なエラー記述を返すことが容易になる。慣習として、エラーは error 型を持つ。」
  • 変更後: 「Goの多値戻りによって、通常の戻り値と並行して詳細なエラー記述を返すことが容易になる。詳細なエラー情報を提供するためにこの機能を使用することは良いスタイルである。例えば、後述するように、os.Open は失敗時に nil ポインタを返すだけでなく、何が問題だったかを説明するエラー値も返す。
    • この変更は、単に多値戻りがエラーハンドリングに「容易」であるという記述から一歩進んで、「良いスタイル」として詳細なエラー情報を提供することの重要性を強調しています。
    • os.Open の具体的な例を導入し、nil ポインタだけでなくエラー値も返すことの必要性を明確に示しています。

変更点2:

 A library writer is free to implement this interface with a
 richer model under the covers, making it possible not only
 to see the error but also to provide some context.
-For example, <code>os.Open</code> returns an <code>os.PathError</code>.
+As mentioned, alongside the usual <code>*os.File</code>
+return value, <code>os.Open</code> also returns an
+error value.
+If the file is opened successfully, the error will be <code>nil</code>,
+but when there is a problem, it will hold an
+<code>os.PathError</code>:
 </p>
 <pre>
 // PathError records an error and the operation and
  • 変更前: 「例えば、os.Openos.PathError を返す。」
  • 変更後:前述のように、通常の *os.File 戻り値と並行して、os.Open もエラー値を返す。ファイルが正常に開かれた場合、エラーは nil になるが、問題がある場合は os.PathError を保持する。
    • この変更は、os.Open の挙動をより詳細に説明しています。特に、成功時には nil エラーが返され、失敗時には具体的な os.PathError が返されるという、Goのエラーハンドリングの慣習を明確に示しています。
    • これにより、開発者は os.Open のような関数がどのようにエラーを報告するのか、そしてそのエラーをどのようにチェックすべきなのかを正確に理解できるようになります。

これらの変更は、Go言語のエラーハンドリングのベストプラクティスを、より明確かつ具体的にドキュメント化することで、開発者がより堅牢で情報量の多いGoプログラムを書くことを奨励しています。

関連リンク

参考にした情報源リンク