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

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

このコミットは、Go言語の公式仕様書である doc/go_spec.html ファイルを修正しています。具体的には、複合リテラルのアドレスを取る操作 (&CompositeLiteral{...}) が言語仕様で明示的に許可されることを追記し、その動作を説明するものです。

コミット

commit 37ab838d3a6544d3661f978a0a9305e61f447403
Author: Rob Pike <r@golang.org>
Date:   Wed Mar 18 22:58:36 2009 -0700

    &Foo{x,y} wasn't in the spec.  This gets it in, dependent on a proper section regarding
    address operators, to follow.
    
    R=rsc
    DELTA=11  (10 added, 0 deleted, 1 changed)
    OCL=26529
    CL=26532

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

https://github.com/golang/go/commit/37ab838d3a6544d3661f978a0a9305e61f447403

元コミット内容

&Foo{x,y} wasn't in the spec. This gets it in, dependent on a proper section regarding
address operators, to follow.

変更の背景

Go言語の初期開発段階において、複合リテラル(例: MyStruct{field: value})の前にアドレス演算子 & を付けて、そのリテラルが生成する値のポインタを直接取得する構文(例: &MyStruct{field: value})が、言語仕様に明示的に記述されていませんでした。この構文はGoのコードベースで実際に使用されており、その動作は直感的ではありますが、公式な言語仕様に記載がないことは、言語の厳密な定義という観点からは不完全でした。

このコミットは、この一般的な慣用句をGo言語仕様に正式に組み込むことを目的としています。これにより、言語のセマンティクスがより明確になり、開発者間の誤解を防ぎ、コンパイラの実装における一貫性を保証します。コミットメッセージにある「dependent on a proper section regarding address operators, to follow」という記述は、アドレス演算子に関するより詳細な説明が後続のコミットで追加される予定であることを示唆しており、言語仕様が段階的に整備されていく過程の一部であることがわかります。

前提知識の解説

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

  • Go言語の複合リテラル (Composite Literals): Go言語において、構造体 (struct)、配列 (array)、スライス (slice)、マップ (map) などの複合型を初期化するための簡潔な構文です。例えば、Point{X: 1, Y: 2}Point 型の構造体を初期化します。複合リテラルは、その場で新しい値を生成し、その値で型を初期化するために使用されます。

  • アドレス演算子 (&): Go言語で変数のメモリアドレスを取得するために使用される単項演算子です。この演算子を適用すると、オペランドの型に対応するポインタ型 (*T) の値が返されます。例えば、&x は変数 x のメモリアドレスを返します。

  • ポインタ (Pointers): Go言語におけるポインタは、変数のメモリアドレスを格納する特殊な型の変数です。ポインタを使用することで、値のコピーではなく、その値が格納されているメモリ上の場所を直接参照することができます。これにより、関数間で大きなデータを効率的に受け渡したり、共有したりすることが可能になります。GoではC/C++のようなポインタ演算は制限されており、より安全に利用できるよう設計されています。

  • Go言語仕様 (Go Language Specification): Go言語の構文、セマンティクス、組み込み関数、パッケージの動作などを厳密に定義した公式文書です。これはGo言語の「真実の源」であり、コンパイラの実装者や言語の挙動を深く理解したい開発者にとって不可欠なリファレンスです。言語の進化に伴い、この仕様書も更新されていきます。

技術的詳細

このコミットは、Go言語仕様の「複合リテラル」に関するセクションに、複合リテラルのアドレスを取る操作 (&CompositeLiteral{...}) のセマンティクスを明示的に追加するものです。

Go言語において、複合リテラルは評価されるたびに新しい値を生成します。例えば、Point{X: 1, Y: 2}というリテラルがコード中で複数回出現した場合、それぞれの出現箇所で異なる Point 型のインスタンスが生成されます。この性質は、リテラルが一時的な値として扱われることを意味します。

このコミットが追加する重要な点は、この「新しい値」に対してアドレス演算子 & を適用できること、そしてその結果が「リテラルの値のユニークなインスタンスへのポインタ」を生成するということです。これは、&CompositeLiteral{...} という構文が、その複合リテラルによって生成された一時的な値をメモリ上に確保し(多くの場合ヒープ上に)、そのメモリ位置へのポインタを返すことを意味します。

この変更は、Go言語の初期段階における言語の厳密な定義と、開発者が直感的に使用していた構文の公式化という側面を持っています。特に、一時的な値のアドレスを取ることが許可されるかどうかという点について、仕様レベルでの明確化が図られています。これにより、コンパイラの実装者はこの構文の挙動を正確に理解し、一貫したコードを生成できるようになります。また、開発者もこの構文が言語の正式な一部であることを確信して使用できます。

コミットメッセージの「dependent on a proper section regarding address operators, to follow」という文言は、このコミットがアドレス演算子に関するより広範な説明の一部であり、将来的にそのセクションが追加されることで、この変更がより完全な文脈の中に位置づけられることを示唆しています。これは、言語仕様が段階的かつ論理的に構築されていくプロセスの一例です。

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

このコミットによる変更は、doc/go_spec.html ファイル内の以下の部分です。

--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1906,7 +1906,17 @@
 one may write
 </p>
 
 <pre>
-pi := Num{Rat{22, 7}, 3.14159, "pi"};
+pi := Num{Rat{22, 7}, 3.14159, "pi"}
+</pre>
+
+<p>
+Since evaluation of a literal creates a new value, taking the address of a
+composite literal (§Address operators) generates a pointer to a unique
+instance of the literal's value.
+</p>
+
+<pre>
+var pi_ptr *Rat = &amp;Rat{22, 7}
 </pre>
 
 <p>

具体的には、既存の複合リテラルの例 (pi := Num{...}) の後に、新しい段落とコード例が追加されています。

コアとなるコードの解説

追加されたHTMLスニペットは、Go言語仕様に以下の重要な情報を組み込んでいます。

  1. 新しい段落 (<p>タグ内):

    • Since evaluation of a literal creates a new value, taking the address of a composite literal (§Address operators) generates a pointer to a unique instance of the literal's value.
    • この文は、複合リテラルが評価されるたびに新しい値が生成されるというGoの基本的なセマンティクスを再確認しています。
    • そして、その複合リテラルの「アドレスを取る」(&演算子を使用する)と、そのリテラルによって生成された値の「ユニークなインスタンス」へのポインタが生成されることを明確に述べています。これは、複合リテラルが一時的なオブジェクトとして扱われ、そのアドレスを取ることで、そのオブジェクトがメモリ上に(多くの場合ヒープ上に)割り当てられ、そのメモリ位置へのポインタが返されることを示唆しています。
    • §Address operators という参照は、アドレス演算子に関するより詳細な説明が別のセクションに存在するか、将来的に追加されることを示しており、言語仕様の構造化された性質を示しています。
  2. 新しいコード例 (<pre>タグ内):

    • var pi_ptr *Rat = &Rat{22, 7}
    • このコード例は、&演算子を使って複合リテラル Rat{22, 7} のアドレスを直接取り、それを *Rat 型のポインタ変数 pi_ptr に代入する具体的な方法を示しています。
    • これにより、pi_ptrRat{22, 7} という値を持つ新しい Rat 構造体のインスタンスを指すようになります。これは、Go言語で構造体のポインタを簡潔に生成する一般的なイディオムであり、このコミットによってその使用が言語仕様で正式に認められたことになります。

これらの追加により、Go言語の複合リテラルとアドレス演算子の組み合わせに関する挙動が、公式な仕様として明確に定義され、言語の厳密性と一貫性が向上しました。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント (特に言語仕様の複合リテラルとアドレス演算子のセクション)
  • Go言語の設計に関する議論やメーリングリストのアーカイブ (Go言語の初期の設計決定に関する背景情報を得るため)