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

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

このコミットは、Go言語の仕様書(doc/go_spec.html)におけるメソッド式のレシーバ型に関する記述を更新するものです。具体的には、メソッド式におけるレシーバ型が括弧で囲むことができるようになったことを反映し、その文法定義(EBNF)と使用例が修正されています。

コミット

commit e06d90136f18fbb1ffa46537d01eb3552f45b0bc
Author: Robert Griesemer <gri@golang.org>
Date:   Thu Dec 6 09:31:42 2012 -0800

    spec: receiver types in method expressions can be parenthesized
    
    Fixes #4457.
    
    R=rsc, iant, r, ken
    CC=golang-dev
    https://golang.org/cl/6862046

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

https://github.com/golang/go/commit/e06d90136f18fbb1ffa46537d01eb3552f45b0bc

元コミット内容

このコミットの目的は、Go言語の仕様において、メソッド式(Method Expression)のレシーバ型(Receiver Type)を括弧で囲むことを許可するように変更し、その変更を仕様書に反映することです。これにより、より柔軟な記述が可能になります。

変更の背景

Go言語では、メソッドは特定の型(レシーバ型)に関連付けられた関数です。メソッド式は、レシーバ型からメソッド関数を取得するための構文を提供します。例えば、T.Mv のように記述することで、型 T のメソッド Mv を関数として取得できます。

このコミット以前は、レシーバ型は TypeName またはポインタ型 (*TypeName) の形式でしか記述できませんでした。しかし、Go言語の他の部分では、型を括弧で囲むことが許容される場合があります。この不整合を解消し、より一貫性のある構文を提供するために、メソッド式のレシーバ型も括弧で囲むことができるように仕様が拡張されました。

コミットメッセージにある Fixes #4457 は、この変更が特定の課題(Issue 4457)を解決するものであることを示唆しています。この課題は、おそらくレシーバ型に括弧を使用できないことによる構文上の制限や、それによって生じる不便さに関するものだったと考えられます。

前提知識の解説

Go言語のメソッドとレシーバ

Go言語において、メソッドは特定の型(レシーバ型)に関連付けられた関数です。メソッドは、レシーバ引数を持つ通常の関数として定義されます。

type MyType int

func (m MyType) MyMethod() {
    // ...
}

func (m *MyType) PointerMethod() {
    // ...
}

上記の例では、MyMethodMyType の値レシーバメソッドであり、PointerMethod*MyType のポインタレシーバメソッドです。

メソッド式 (Method Expressions)

メソッド式は、レシーバ型からメソッド関数を取得するための構文です。これは、特定のインスタンスにバインドされていない「関数テンプレート」のようなものです。メソッド式によって取得された関数は、最初の引数としてレシーバを受け取ります。

例: T.Mv は、型 T のメソッド Mv を表すメソッド式です。この式の結果は、func(T, args...) のようなシグネチャを持つ関数となります。

type T int

func (t T) Mv(a int) int {
    return int(t) + a
}

func main() {
    var t T = 10
    // 通常のメソッド呼び出し
    t.Mv(7) // => 17

    // メソッド式
    f := T.Mv // f は func(T, int) int 型の関数
    f(t, 7)   // => 17
}

EBNF (Extended Backus-Naur Form)

EBNFは、プログラミング言語の構文を記述するためのメタ言語です。Go言語の仕様書でも、構文規則を定義するためにEBNFが使用されています。

  • | (パイプ): 論理OR。選択肢を示します。
  • () (括弧): グループ化。
  • * (アスタリスク): 0回以上の繰り返し。

技術的詳細

このコミットの主要な変更点は、Go言語の仕様書(doc/go_spec.html)における ReceiverType のEBNF定義の変更です。

変更前:

ReceiverType  = TypeName | "(" "*" TypeName ")" .

これは、ReceiverTypeTypeName(例: T)または (*TypeName)(例: (*T))のいずれかであることを意味していました。

変更後:

ReceiverType  = TypeName | "(" "*" TypeName ")" | "(" ReceiverType ")" .

この変更により、ReceiverType の定義に | "(" ReceiverType ")" が追加されました。これは、ReceiverType 自体をさらに括弧で囲むことができるようになったことを意味します。つまり、T だけでなく、(T)((T)) のように、任意の深さで括弧をネストしてレシーバ型を記述することが可能になります。

この変更は、メソッド式の構文解析において、レシーバ型がより柔軟に表現されることを可能にします。例えば、T.Mv と同様に (T).Mv も有効なメソッド式として認識されるようになります。

また、仕様書の例も更新され、この新しい構文がどのように使用されるかを示しています。

変更前の例の記述: these three invocations are equivalent:

変更後の例の記述: these five invocations are equivalent:

追加された例は以下の通りです。

  • (T).Mv(t, t): 型 T を括弧で囲んだ形式でメソッド式を呼び出す例。
  • f2 := (T).Mv; f2(t, 7): 括弧で囲んだ型からメソッド式を取得し、それを変数に代入して呼び出す例。

これらの例は、レシーバ型を括弧で囲むことが、直接のメソッド呼び出しと、メソッド式を変数に代入してからの呼び出しの両方で有効であることを明確に示しています。

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

変更は doc/go_spec.html ファイルに集中しており、Go言語の仕様書の一部を修正しています。

--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -3316,7 +3316,7 @@ argument that is the receiver of the method.

 <pre class="ebnf">
 MethodExpr    = ReceiverType "." MethodName .
-ReceiverType  = TypeName | "(" "*" TypeName ")" .
+ReceiverType  = TypeName | "(" "*" TypeName ")" | "(" ReceiverType ")" .
 </pre>

 <p>
@@ -3353,13 +3353,15 @@ func(tv T, a int) int

 <p>
 That function may be called normally with an explicit receiver, so
-these three invocations are equivalent:
+these five invocations are equivalent:
 </p>

 <pre>
 t.Mv(7)
 T.Mv(t, 7)
-f := T.Mv; f(t, 7)
+(T).Mv(t, t)
+f1 := T.Mv; f1(t, 7)
+f2 := (T).Mv; f2(t, 7)
 </pre>

 <p>

コアとなるコードの解説

  1. EBNF定義の変更: ReceiverType の定義が TypeName | "(" "*" TypeName ")" | "(" ReceiverType ")" に変更されました。これにより、ReceiverType が再帰的に括弧で囲むことが可能になり、(T)(*T) のような形式だけでなく、((T))((*T)) のような形式も文法的に正しくなりました。これは、Goコンパイラがこれらの新しい形式のレシーバ型を正しく解析できるようになることを意味します。

  2. 例の追加: 既存のメソッド呼び出しの等価性の例に、(T).Mv(t, t)f2 := (T).Mv; f2(t, 7) の2つの新しいパターンが追加されました。これらの例は、括弧で囲まれたレシーバ型がどのようにメソッド式で使用され、それが従来の形式と同等に機能するかを具体的に示しています。これにより、仕様の変更が開発者にとってより理解しやすくなります。

この変更は、Go言語の構文の一貫性を高め、開発者がより自然な方法でメソッド式を記述できるようにすることを目的としています。

関連リンク

参考にした情報源リンク