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

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

このコミットで変更されたファイルは doc/go_spec.txt です。これはGo言語の仕様書(Go Language Specification)の草稿、または初期バージョンの一部であると考えられます。Go言語の設計と機能に関する公式なドキュメントであり、言語の構文、セマンティクス、標準ライブラリの動作などを定義する重要な役割を担っています。このファイルへの変更は、Go言語の仕様に関する記述の追加や修正を意味します。

コミット

  • コミットハッシュ: 9f4a27cbe6cc46a82bb9f3e0cb23dda10819be15
  • 作者: Robert Griesemer (gri@golang.org)
  • コミット日時: 2009年1月16日 金曜日 15:44:08 -0800
  • コミットメッセージ: - added TODO

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

https://github.com/golang/go/commit/9f4a27cbe6cc46a82bb9f3e0cb23dda10819be15

元コミット内容

    - added TODO
    
    R=r
    DELTA=3  (3 added, 0 deleted, 0 changed)
    OCL=23003
    CL=23003

変更の背景

このコミットは、Go言語の初期開発段階において、言語仕様の記述がまだ進行中であったことを示しています。Go言語は2009年11月に一般公開されましたが、このコミットはその約10ヶ月前のものです。

変更の背景にあるのは、Go言語の複合リテラル(Composite Literals)における構造体(struct)の初期化に関する特定のケース、特に「パッケージ外部からのタプル形式の代入(tuple assignments)が、プライベートフィールド(unexported fields)を持つ構造体に対して不正である」という点について、仕様書に明記する必要があるという認識です。

Go言語では、構造体のフィールドを初期化する際に、フィールド名を明示的に指定する方法(T{a: 1, b: 2})と、フィールド名を省略して順番に値を指定する方法(T{1, 2})があります。後者の「タプル形式」の初期化は、構造体のすべてのフィールドがエクスポートされている(つまり、パッケージ外部からアクセス可能である)場合にのみ許可されるべきです。もしプライベートフィールドが含まれている場合、そのフィールドはパッケージ外部からは見えないため、タプル形式での初期化は曖昧さや意図しない動作を引き起こす可能性があります。

このTODOは、このような潜在的な問題を明確にし、言語の設計意図を仕様書に反映させるためのタスクとして追加されました。これは、言語の整合性と明確性を保つ上で重要なステップでした。

前提知識の解説

このコミットの理解には、以下のGo言語の概念が前提となります。

  • Go言語の仕様書 (Go Language Specification): Go言語の構文、セマンティクス、標準ライブラリの動作などを公式に定義する文書です。言語の「憲法」のようなもので、コンパイラの実装やプログラマのコード記述の指針となります。doc/go_spec.txt はその初期のテキスト形式のバージョンです。
  • 構造体 (Struct): 異なる型のフィールドをまとめた複合データ型です。例えば、type Person struct { Name string; Age int } のように定義します。
  • フィールド (Field): 構造体内で定義される変数です。
  • プライベートフィールド / エクスポートされていないフィールド (Unexported Fields): Go言語では、フィールド名(または関数名、型名など)の最初の文字が小文字で始まる場合、そのフィールドは定義されたパッケージ内でのみアクセス可能です。これを「エクスポートされていない(unexported)」、あるいは慣習的に「プライベート」と呼びます。パッケージ外部からは直接アクセスできません。
  • パッケージ (Package): Go言語のコードを整理する単位です。関連する機能や型をまとめるために使用されます。パッケージは、コードの再利用性、モジュール性、名前空間の管理に役立ちます。
  • 複合リテラル (Composite Literals): 構造体、配列、スライス、マップなどの複合型の値を生成するための構文です。例えば、構造体の複合リテラルは MyStruct{field1: value1, field2: value2} のように書きます。
  • タプル (Tuple): 厳密にはGo言語に「タプル型」という概念はありませんが、この文脈では、構造体の複合リテラルでフィールド名を省略して値を順番に指定する形式(例: T{1, 2})を指しています。これは、あたかもタプルのように値の並びで構造体を初期化するような振る舞いをすることから、このように表現されています。

技術的詳細

このTODOが指摘している問題は、Go言語の複合リテラルにおける構造体の初期化の曖昧さに関するものです。

Go言語の構造体複合リテラルには、以下の2つの主要な形式があります。

  1. フィールド名を明示的に指定する形式 (Keyed elements):

    type T struct { a int; b int }
    t := T{a: 1, b: 2}
    

    この形式では、フィールド名とそれに対応する値を明示的に指定します。フィールドの順序は任意であり、指定されていないフィールドはゼロ値で初期化されます。

  2. フィールド名を省略して順番に指定する形式 (Unkeyed elements):

    type T struct { a int; b int }
    t := T{1, 2} // aが1、bが2で初期化される
    

    この形式では、構造体のフィールドが宣言された順序で値を指定します。すべてのフィールドに値を指定する必要があります。

問題となるのは、後者の「フィールド名を省略して順番に指定する形式」が、プライベートフィールド(エクスポートされていないフィールド)を持つ構造体に対して使用された場合です。

例として、以下のような構造体を考えます。

package P // 別のパッケージ

type T struct {
    a int // エクスポートされているフィールド
    b int // エクスポートされていない(プライベート)フィールド
}

別のパッケージからこの構造体 P.T を初期化しようとする場合を想定します。

もし P.T{1, 2} のようにタプル形式で初期化しようとすると、Go言語の設計思想と矛盾が生じます。なぜなら、パッケージ P の外部からはフィールド b がプライベートであるため、その存在や型を知るべきではないからです。しかし、タプル形式の初期化では、フィールドの順序と数に依存するため、プライベートフィールドの存在を暗黙的に前提としてしまいます。

コミットメッセージのTODOにある P.T{1, 2} illegal since same as P.T{a: 1, b: 2} for a T struct { a b int } という記述は、この問題を明確にしています。つまり、もし Tab という2つのフィールドを持つ構造体である場合、P.T{1, 2} というタプル形式の初期化は、あたかも P.T{a: 1, b: 2} とフィールド名を明示的に指定したかのように振る舞うことを意図しているように見えます。しかし、b がプライベートフィールドである場合、パッケージ外部から b を指定することはできません。したがって、タプル形式の初期化も同様に不正であるべきだ、という論理です。

このTODOは、Go言語の設計原則である「エクスポートされていない識別子はパッケージ外部からは見えない」という原則を、複合リテラルの初期化にも厳密に適用する必要があることを示唆しています。これにより、言語の整合性が保たれ、予期せぬ動作やセキュリティ上の懸念が排除されます。

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

--- a/doc/go_spec.txt
+++ b/doc/go_spec.txt
@@ -36,6 +36,9 @@ Wish list:
 
 
 Todo's:
+[ ] document illegality of package-external tuple assignments to structs
+\tw/ private fields: P.T{1, 2} illegal since same as P.T{a: 1, b: 2} for
+\ta T struct { a b int }.
 [ ] clarification on interface types, rules
 [ ] clarify slice rules
 [ ] clarify tuples

コアとなるコードの解説

この変更は、doc/go_spec.txt ファイルの "Todo's" セクションに新しい項目を追加しています。追加されたTODOは以下の通りです。

[ ] document illegality of package-external tuple assignments to structs
    w/ private fields: P.T{1, 2} illegal since same as P.T{a: 1, b: 2} for
    a T struct { a b int }.

このTODOは、Go言語の仕様書において、以下の点を明確に文書化する必要があることを示しています。

  1. パッケージ外部からのタプル形式の構造体初期化の不正性:

    • P.T{1, 2} のような形式(フィールド名を省略して値を順番に指定する形式)で、別のパッケージ P で定義された構造体 T を初期化しようとする場合。
    • この構造体 T が、エクスポートされていない(プライベートな)フィールドを含んでいる場合。
    • このような初期化は不正(illegal)であるべきである。
  2. 不正である理由の明確化:

    • その理由は、P.T{1, 2} という形式が、内部的には P.T{a: 1, b: 2} のようにフィールド名を明示的に指定する形式と同じ意味を持つためである。
    • しかし、もし Tab というフィールドを持ち、b がプライベートフィールドである場合、パッケージ外部からは b を直接参照したり、その値を指定したりすることはできない。
    • したがって、プライベートフィールドを含む構造体に対して、パッケージ外部からタプル形式で初期化を試みることは、プライベートな内部構造を露呈させることになり、Go言語のアクセス制御の原則に反するため、許可されるべきではない。

このTODOは、Go言語の設計者が、言語の整合性と安全性を確保するために、複合リテラルの挙動に関する潜在的な曖昧さを早期に特定し、仕様として明確化しようとしていたことを示しています。最終的に、Go言語の仕様では、エクスポートされていないフィールドを持つ構造体に対して、パッケージ外部からフィールド名を省略した複合リテラルを使用することは許可されていません。

関連リンク

参考にした情報源リンク