[インデックス 1363] ファイルの概要
このコミットは、Go言語の仕様書 doc/go_spec.txt
におけるメソッドレシーバの定義を更新するものです。具体的には、メソッドレシーバの識別子(変数名)がオプションであることを明示するように文法定義が変更されました。これにより、メソッド内でレシーバの値を使用しない場合に、識別子を省略できるという言語機能が仕様に反映されました。
コミット
commit 6ccca61510ac3e3a9e96019bc6bfb1286cac080e
Author: Robert Griesemer <gri@golang.org>
Date: Thu Dec 18 13:29:11 2008 -0800
- receiver ident may be optional
R=r
DELTA=5 (2 added, 0 deleted, 3 changed)
OCL=21508
CL=21510
---
doc/go_spec.txt | 8 +++++---\n 1 file changed, 5 insertions(+), 3 deletions(-)\n
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/6ccca61510ac3e3a9e96019bc6bfb1286cac080e
元コミット内容
- receiver ident may be optional
変更の背景
Go言語の設計初期段階において、メソッドのレシーバ(メソッドが紐付けられる型インスタンス)を宣言する際に、そのレシーバの識別子(変数名)が常に必要であるという初期の設計がありました。しかし、実際のプログラミングにおいては、メソッド内でレシーバの値自体は使用しないが、その型にメソッドを紐付ける必要があるというケースが頻繁に発生します。
例えば、インターフェースを満たすために特定のシグネチャを持つメソッドを実装する必要があるが、そのメソッドのロジックがレシーバの状態に依存しない場合などが挙げられます。このような場合、レシーバの識別子を宣言することは冗長であり、コードの可読性を損ねる可能性がありました。
このコミットは、このような実用的なニーズに応えるため、レシーバの識別子を省略可能とすることで、より簡潔で表現力豊かなコード記述を可能にするための仕様変更を反映したものです。これは、Go言語が「シンプルさ」と「実用性」を重視する設計哲学に基づいていることの一例と言えます。
前提知識の解説
Go言語のメソッドとレシーバ
Go言語において、メソッドは特定の型に関連付けられた関数です。メソッドは、その型(レシーバ型)のインスタンスに対して操作を行うために使用されます。メソッドの宣言は func (receiver) MethodName(parameters) (results)
の形式を取ります。
- レシーバ (Receiver): メソッドが操作する値(またはポインタ)を指します。レシーバは、メソッドのシグネチャの一部として括弧
()
内に宣言されます。レシーバは、値レシーバ(func (t MyType) ...
)とポインタレシーバ(func (t *MyType) ...
)の2種類があります。 - 識別子 (Identifier): プログラミング言語において、変数、関数、型などの名前を識別するために使用される文字列です。このコミットの文脈では、レシーバの変数名(例:
t
やself
など)を指します。
言語仕様書と文法定義
プログラミング言語の「仕様書」は、その言語がどのように動作するか、どのような構文を持つかを厳密に定義した公式文書です。Go言語の仕様書は doc/go_spec.txt
(現在は go.dev/ref/spec
に移行) であり、言語のあらゆる側面が記述されています。
仕様書の中では、言語の構文(シンタックス)を定義するために、バッカス・ナウア記法 (BNF) やその派生形のような形式文法が用いられることがあります。このコミットで変更されている Receiver
の定義も、Go言語の構文規則の一部です。
identifier
: 識別子(変数名など)を表す構文要素。[ ... ]
: 形式文法において、角括弧[]
はその中の要素がオプション(省略可能)であることを示します。
この変更は、Go言語のコンパイラやツールが、レシーバの識別子が省略されたメソッド宣言を正しく解釈できるようにするための基盤となります。
技術的詳細
このコミットの核心は、Go言語の仕様書 doc/go_spec.txt
内の Receiver
の文法定義の変更にあります。
変更前:
Receiver = "(" identifier [ "*" ] TypeName ")"
変更後:
Receiver = "(" [ identifier ] [ "*" ] TypeName ")"
この変更は非常に小さいですが、Go言語の構文規則に大きな影響を与えます。
-
identifier
のオプション化: 変更前はidentifier
が必須要素として定義されていました。つまり、レシーバを宣言する際には必ず変数名を指定する必要がありました。変更後は[ identifier ]
となり、identifier
が角括弧で囲まれています。これは形式文法において「この要素は省略可能である」ことを意味します。 -
意味論的影響: この文法変更により、Go言語のコンパイラは以下のようなメソッド宣言を合法として扱えるようになります。
type MyType struct{} // レシーバ識別子を省略したメソッド func (_ MyType) DoSomething() { // MyType の値は使用しないが、MyType に紐付くメソッドとして定義 fmt.Println("Doing something without using the receiver.") } // 通常のレシーバ識別子を持つメソッド func (m MyType) DoAnotherThing() { fmt.Println("Doing another thing with receiver:", m) }
慣例として、Goでは使用しない変数にはアンダースコア
_
を割り当てることがありますが、この変更により、レシーバの識別子自体を完全に省略できるようになりました。これは、特にインターフェースの実装などで、レシーバの値が不要な場合にコードをより簡潔に記述できるという利点があります。 -
仕様の正確性: この変更は、Go言語の実際のコンパイラの挙動と仕様書との整合性を保つためにも重要です。言語が進化し、新しい機能や慣用句が導入されるたびに、その変更が正確に仕様書に反映される必要があります。
コアとなるコードの変更箇所
変更は doc/go_spec.txt
ファイル内で行われています。
--- a/doc/go_spec.txt
+++ b/doc/go_spec.txt
@@ -3,7 +3,7 @@ The Go Programming Language Specification (DRAFT)
Robert Griesemer, Rob Pike, Ken Thompson
-(December 17, 2008)
+(December 18, 2008)
----
@@ -3045,10 +3045,12 @@ as a type name, or as a pointer to a type name. The type specified by the
type name is called ``receiver base type''. The receiver base type must be a
type declared in the current file, and it must not be a pointer type.\n The method is said to be ``bound'' to the receiver base type; specifically\n-it is declared within the scope of that type (§Type declarations).\n+it is declared within the scope of that type (§Type declarations). If the\n+receiver value is not needed inside the method, its identifier may be omitted\n+in the declaration.\n \n \tMethodDecl = "func" Receiver identifier FunctionType [ Block ] .\n-\tReceiver = "(" identifier [ "*" ] TypeName ")" .\n+\tReceiver = "(" [ identifier ] [ "*" ] TypeName ")" .\n \n All methods bound to a receiver base type must have the same receiver type:\n Either all receiver types are pointers to the base type or they are the base\n```
## コアとなるコードの解説
上記の差分は、Go言語の仕様書 `doc/go_spec.txt` の2箇所を変更しています。
1. **日付の更新**:
`- (December 17, 2008)`
`+ (December 18, 2008)`
これは単に仕様書の改訂日を更新したものです。
2. **レシーバ識別子のオプション化に関する説明の追加**:
`- it is declared within the scope of that type (§Type declarations).`
`+ it is declared within the scope of that type (§Type declarations). If the`
`+ receiver value is not needed inside the method, its identifier may be omitted`
`+ in the declaration.`
この変更は、メソッドがレシーバ型にバインドされることについての既存の説明に、**「もしメソッド内でレシーバの値が必要ない場合、その識別子を宣言で省略できる」**という新しい文言を追加しています。これは、後述の文法変更の理由と結果を説明するものです。
3. **`Receiver` 文法定義の変更**:
`- Receiver = "(" identifier [ "*" ] TypeName ")" .`
`+ Receiver = "(" [ identifier ] [ "*" ] TypeName ")" .`
これがこのコミットの最も重要な変更点です。
* 変更前は、`identifier` が括弧 `()` の直後に記述されており、レシーバの識別子が必須であることを示していました。
* 変更後は、`identifier` が角括弧 `[]` で囲まれています。形式文法において、角括弧は「その要素がオプション(省略可能)である」ことを意味します。
この変更により、Go言語のメソッド宣言において、レシーバの識別子を記述するかどうかを選択できるようになりました。例えば、`func (t MyType)` と書くこともできますし、`func (MyType)` と書くこともできるようになります(ただし、後者の形式ではメソッド内でレシーバの値にアクセスすることはできません)。
これらの変更は、Go言語の構文がより柔軟になり、開発者がレシーバの値を使用しない場合に冗長な識別子を記述する必要がなくなることを意味します。
## 関連リンク
* Go Programming Language Specification: [https://go.dev/ref/spec](https://go.dev/ref/spec) (現在のGo言語仕様書)
* Go言語のメソッドに関する公式ドキュメント: [https://go.dev/tour/methods/1](https://go.dev/tour/methods/1)
## 参考にした情報源リンク
* Go言語の仕様書 `doc/go_spec.txt` の内容
* Go言語のメソッドとレシーバに関する一般的な知識
* 形式文法(BNFなど)における `[]` の意味に関する知識