[インデックス 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.File
と nil
を返し、失敗時には nil
と具体的な os.PathError
を返すという挙動を例に挙げることで、このベストプラクティスを明確に示しています。
Fixes #1963
という記述から、この変更がGoのIssueトラッカーで報告された特定の課題(Issue 1963)を解決するために行われたことがわかります。このIssueは、おそらく effective_go.html
のエラーに関する説明が不十分である、または誤解を招く可能性があるという指摘だったと推測されます。
前提知識の解説
このコミットを理解するためには、以下のGo言語の基本的な概念と慣習を理解しておく必要があります。
-
多値戻り (Multiple Return Values): Go言語の関数は、複数の値を返すことができます。これは、エラーハンドリングにおいて非常に重要な機能です。例えば、
value, err := someFunction()
のように、通常の戻り値とエラー値を同時に受け取ることができます。 -
error
インターフェース: Go言語には、エラーを表すための組み込みインターフェースerror
があります。type error interface { Error() string }
このインターフェースは、
Error() string
メソッドを一つだけ持ちます。このメソッドは、エラーの人間が読める形式の文字列表現を返します。Goの標準ライブラリやユーザー定義のエラー型は、このインターフェースを実装することで、エラーとして扱われます。 -
nil
とエラーハンドリング: Goの慣習では、関数が正常に実行された場合、error
型の戻り値はnil
になります。nil
は、ポインタ、インターフェース、マップ、スライス、チャネル、関数などのゼロ値であり、「値がない」ことを意味します。エラーが発生した場合、error
型の戻り値はnil
ではない具体的なエラーオブジェクトになります。 一般的なエラーチェックのパターンは以下のようになります。result, err := someFunction() if err != nil { // エラー処理 fmt.Println("Error:", err) return } // 正常処理 fmt.Println("Result:", result)
-
os.Open
の挙動:os.Open
は、ファイルを開くためのGoの標準ライブラリ関数です。そのシグネチャは以下のようになっています。func Open(name string) (*File, error)
この関数は、成功すると
*os.File
型のファイルディスクリプタとnil
エラーを返します。ファイルが見つからない、アクセス権がないなどの理由で失敗すると、nil
の*os.File
と、具体的なerror
型の値(例えば*os.PathError
)を返します。 -
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
ポインタを返すだけで十分であるという誤解を生む可能性がありました。
変更後では、以下の点が明確に強調されています。
- 「詳細なエラー情報を提供するためにこの機能(多値戻り)を使用することは良いスタイルである」 という文言が追加されました。これにより、単にエラーを検出するだけでなく、その詳細を伝えることの重要性が強調されます。
os.Open
の例がより詳細に説明されました。変更前は「os.Open
はos.PathError
を返す」とだけ書かれていましたが、変更後では 「os.Open
は失敗時にnil
ポインタを返すだけでなく、何が問題だったかを説明するエラー値も返す」 と明記されています。- さらに、
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.Open
はos.PathError
を返す。」 - 変更後: 「前述のように、通常の
*os.File
戻り値と並行して、os.Open
もエラー値を返す。ファイルが正常に開かれた場合、エラーはnil
になるが、問題がある場合はos.PathError
を保持する。」- この変更は、
os.Open
の挙動をより詳細に説明しています。特に、成功時にはnil
エラーが返され、失敗時には具体的なos.PathError
が返されるという、Goのエラーハンドリングの慣習を明確に示しています。 - これにより、開発者は
os.Open
のような関数がどのようにエラーを報告するのか、そしてそのエラーをどのようにチェックすべきなのかを正確に理解できるようになります。
- この変更は、
これらの変更は、Go言語のエラーハンドリングのベストプラクティスを、より明確かつ具体的にドキュメント化することで、開発者がより堅牢で情報量の多いGoプログラムを書くことを奨励しています。
関連リンク
- Go Issue 1963: https://github.com/golang/go/issues/1963 (このコミットが修正したIssue)
- Go Code Review 97360045: https://golang.org/cl/97360045 (このコミットのコードレビューページ)
- Effective Go - Errors: https://go.dev/doc/effective_go#errors (現在の
effective_go.html
のエラーセクション)
参考にした情報源リンク
- Go言語公式ドキュメント: https://go.dev/doc/
- Go言語の
error
インターフェースに関する情報: https://go.dev/blog/error-handling-and-go os.Open
のドキュメント: https://pkg.go.dev/os#Openos.PathError
のドキュメント: https://pkg.go.dev/os#PathError