[インデックス 17271] ファイルの概要
このコミットは、Go言語の仕様書 doc/go_spec.html
に、アドレス演算子 &
の振る舞いに関する重要な変更、特に評価対象の式がパニックを引き起こす場合の挙動について追記するものです。具体的には、&x
の評価が x
の評価によってランタイムパニックを引き起こす場合、&x
自体もパニックを引き起こすことを明確にしています。
コミット
commit 5ce78b7cd281b187a06dcdb9ea9d1de8419db297
Author: Russ Cox <rsc@golang.org>
Date: Thu Aug 15 14:33:26 2013 -0400
spec: &x panics if x does
See golang.org/s/go12nil for the extended version.
R=golang-dev, r, adonovan
CC=golang-dev
https://golang.org/cl/12964043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/5ce78b7cd281b187a06dcdb9ea9d1de8419db297
元コミット内容
spec: &x panics if x does
See golang.org/s/go12nil for the extended version.
R=golang-dev, r, adonovan
CC=golang-dev
https://golang.org/cl/12964043
変更の背景
このコミットは、Go 1.2における重要な仕様変更、特に「Go 1.2 Field Selectors and Nil Checks」という設計ドキュメント (golang.org/s/go12nil
) に基づいています。Go言語では、ポインタのデリファレンス(*x
)がnilポインタに対して行われた場合にランタイムパニックが発生することは明確でした。しかし、アドレス演算子 &
を使用して、nilポインタのフィールドのアドレスを取得しようとする場合(例: &x.Field
、ここで x
はnilポインタ)、その挙動が曖昧でした。
Go 1.2以前は、このようなケースで一貫性のない、あるいは予期せぬ動作が発生する可能性がありました。例えば、&x.Field
がnilポインタに対して実行された場合、フィールドのオフセットによっては、有効なポインタのように見えてしまうことがあり、これが後続のコードで問題を引き起こす可能性がありました。この曖昧さは、開発者が予測可能なコードを書く上で障害となり、潜在的なバグの温床となっていました。
このコミットは、このような曖昧さを解消し、Go言語の安全性と予測可能性を高めることを目的としています。&x
の評価が x
の評価によってパニックを引き起こす場合、&x
自体もパニックを引き起こすという明確なルールを導入することで、開発者はnilポインタの扱いに関してより堅牢なコードを記述できるようになります。
前提知識の解説
- アドレス演算子 (
&
): Go言語において、変数のメモリアドレスを取得するために使用される演算子です。例えば、&v
は変数v
のアドレスを返します。 - ポインタ (
*T
): メモリアドレスを格納する変数型です。*T
は型T
の値へのポインタを表します。 - デリファレンス演算子 (
*
): ポインタが指すメモリアドレスに格納されている値を取得するために使用される演算子です。例えば、*p
はポインタp
が指す値を返します。 - ランタイムパニック (Run-time panic): Goプログラムの実行中に発生する回復不可能なエラーです。例えば、nilポインタのデリファレンス、配列の範囲外アクセスなどがパニックを引き起こします。パニックが発生すると、通常のプログラムフローは中断され、defer関数が実行された後、プログラムは終了します(recoverされない限り)。
- Go言語の仕様 (Go Language Specification): Go言語の構文、セマンティクス、および標準ライブラリの動作を定義する公式ドキュメントです。言語の挙動に関する最終的な権威となります。
golang.org/s/go12nil
: これは、Go 1.2におけるフィールドセレクタとnilチェックに関する設計ドキュメントへのショートリンクです。Go言語の重要な変更や新機能は、通常、このような設計ドキュメントで提案され、コミュニティのレビューを経て実装されます。このドキュメントは、nilポインタに対するフィールド選択の挙動の変更について詳細に説明しています。
技術的詳細
このコミットの技術的な核心は、Go言語の仕様書におけるアドレス演算子 &
のセクションに、以下の文言を追加することです。
If the evaluation of
x
would cause a run-time panic, then the evaluation of&x
does too.
これは、アドレス演算子 &
のオペランド x
の評価がランタイムパニックを引き起こす場合、&x
自体の評価も同様にランタイムパニックを引き起こすことを明確に規定しています。
具体的な例として、コミットで追加されたコードスニペットを見てみましょう。
var x *int = nil
*x // causes a run-time panic
&*x // causes a run-time panic
var x *int = nil
:x
はint
型へのポインタとして宣言され、nil
で初期化されます。つまり、x
は何も指していません。*x
: ここでx
をデリファレンスしようとすると、nil
ポインタのデリファレンスとなり、Go言語の既存のルールに従ってランタイムパニックが発生します。&*x
: この行がこのコミットの変更のポイントです。以前は、&*x
の挙動が曖昧でした。しかし、このコミットによって追加された仕様により、*x
の評価がパニックを引き起こすため、&*x
の評価もパニックを引き起こすことが保証されます。
この変更は、Go言語の型システムとランタイムの整合性を高めるものです。アドレス演算子 &
は、そのオペランドが有効なメモリ位置を指していることを前提とします。もしオペランドの評価自体が不正な状態(この場合はnilポインタのデリファレンス)を引き起こすのであれば、そのアドレスを取得しようとする操作もまた不正であると見なされるべきだという論理に基づいています。
これにより、開発者はnilポインタのデリファレンスがアドレス演算子の内部で発生した場合でも、予測可能なパニック挙動を期待できるようになり、デバッグが容易になり、より堅牢なプログラムを構築できるようになります。
コアとなるコードの変更箇所
変更は doc/go_spec.html
ファイルに対して行われています。
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -3287,7 +3287,10 @@ or an array indexing operation of an addressable array.
As an exception to the addressability requirement, <code>x</code> may also be a
(possibly parenthesized)
<a href="#Composite_literals">composite literal</a>.
+If the evaluation of <code>x</code> would cause a <a href="#Run_time_panics">run-time panic</a>,
+then the evaluation of <code>&x</code> does too.
</p>
+
<p>
For an operand <code>x</code> of pointer type <code>*T</code>, the pointer
indirection <code>*x</code> denotes the value of type <code>T</code> pointed
@@ -3302,6 +3305,10 @@ will cause a <a href="#Run_time_panics">run-time panic</a>.
&Point{2, 3}
*p
*pf(x)
+
+var x *int = nil
+*x // causes a run-time panic
+&*x // causes a run-time panic
</pre>
具体的には、以下の2点が変更されています。
- アドレス演算子
&
の説明セクションに、パニックに関する新しいルールが追加されました。If the evaluation of <code>x</code> would cause a <a href="#Run_time_panics">run-time panic</a>, then the evaluation of <code>&x</code> does too.
- この新しいルールを説明するための具体的なコード例が追加されました。
var x *int = nil *x // causes a run-time panic &*x // causes a run-time panic
コアとなるコードの解説
追加されたHTMLのテキストは、Go言語の仕様書におけるアドレス演算子 &
のセクションに、その挙動に関する重要な補足説明を加えるものです。
If the evaluation of x would cause a run-time panic, then the evaluation of &x does too.
この一文は、&x
という式を評価する際に、まず x
の部分が評価され、もしその x
の評価自体がランタイムパニックを引き起こすような状況であれば、その &x
という式全体もランタイムパニックを引き起こす、ということを明確にしています。
例えば、x
が *p
のようなポインタのデリファレンスであり、p
が nil
である場合、*p
の評価はランタイムパニックを引き起こします。この新しい仕様により、&*p
という式も同様にパニックを引き起こすことが保証されます。これは、アドレス演算子がそのオペランドが有効なメモリ位置を指していることを前提としているため、オペランドの評価が不正な状態(nilポインタのデリファレンス)を引き起こすのであれば、そのアドレスを取得しようとする操作もまた不正であると見なされるべきだという論理に基づいています。
追加されたコード例は、この新しいルールを具体的に示しています。
var x *int = nil
*x // causes a run-time panic
&*x // causes a run-time panic
var x *int = nil
:x
はnil
ポインタです。*x
:nil
ポインタのデリファレンスは、Goの既存のルールによりパニックを引き起こします。&*x
: ここがポイントです。&
演算子のオペランドは*x
です。上記の行で示されているように、*x
の評価はパニックを引き起こします。したがって、この新しい仕様により、&*x
の評価もパニックを引き起こすことが保証されます。
この変更は、Go言語の予測可能性と堅牢性を向上させ、開発者がnilポインタの扱いに関してより安全なコードを記述できるようにするための重要なステップです。
関連リンク
- Go 1.2 Field Selectors and Nil Checks (golang.org/s/go12nil): このコミットの背景にある設計ドキュメントです。nilポインタに対するフィールド選択の挙動の変更について詳細に説明されています。
- Go issue 4238: この仕様変更に関する議論が行われたGoのIssueトラッカーのエントリです。
- Gerrit Change 12964043: このコミットに対応するGerritの変更セットです。