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

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

このコミットは、Go言語の仕様書(doc/go_spec.html)における短い変数宣言(short variable declaration)の挙動に関する記述を明確にするための変更です。特に、変数の再宣言が許可される条件について、より厳密な定義が追加されています。

コミット

commit f1cc0f44e384ff33179a2cc6d19369237cdc64cd
Author: Robert Griesemer <gri@golang.org>
Date:   Wed Jan 9 11:31:32 2013 -0800

    spec: clarify short variable declaration corner cases
    
    Fixes #4612.
    
    R=rsc, iant, ken, r
    CC=golang-dev
    https://golang.org/cl/7076043

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

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

元コミット内容

spec: clarify short variable declaration corner cases

Fixes #4612.

R=rsc, iant, ken, r
CC=golang-dev
https://golang.org/cl/7076043

変更の背景

このコミットは、Go言語の短い変数宣言(:=)における変数の再宣言に関する曖昧さを解消するために行われました。特に、同じブロック内で変数を再宣言する際の条件について、既存の仕様記述では誤解を招く可能性がありました。コミットメッセージにある Fixes #4612 は、この変更が特定の課題(issue)を解決するものであることを示唆していますが、Goの公式イシュートラッカーで直接的な関連が見つからなかったため、具体的な問題の詳細は不明です。しかし、一般的にこのような仕様の明確化は、言語の挙動に関する開発者の混乱を避け、コンパイラの実装における一貫性を保つために重要です。

Go言語では、短い変数宣言は非常に便利ですが、その挙動、特に再宣言のルールは、C++などの他の言語の変数宣言とは異なるため、注意が必要です。このコミットは、その「コーナーケース」(特殊な状況や境界条件)を明確にすることで、言語仕様の堅牢性を高めることを目的としています。

前提知識の解説

Go言語の短い変数宣言(Short Variable Declaration)

Go言語には、var キーワードを使った通常の変数宣言の他に、:= 演算子を使った「短い変数宣言」という便利な機能があります。

例:

x := 10 // x は int 型として宣言され、10 で初期化される
name := "Alice" // name は string 型として宣言され、"Alice" で初期化される

この短い変数宣言は、以下の特徴を持ちます。

  1. 型推論: 変数の型を明示的に指定する必要がなく、初期値から型が推論されます。
  2. 宣言と初期化の同時実行: 変数の宣言と初期化を同時に行います。
  3. スコープ: 変数が宣言されたブロック({} で囲まれた範囲)内でのみ有効です。

変数の再宣言(Redeclaration)

Go言語の短い変数宣言の重要な特徴の一つに、再宣言の許可があります。これは、通常の変数宣言では許されない挙動です。

一般的なプログラミング言語では、同じスコープ内で同じ名前の変数を複数回宣言することはエラーとなります。しかし、Goの短い変数宣言では、特定の条件下で既存の変数を「再宣言」することができます。これは厳密には「再宣言」というよりも「既存変数への再割り当てと新規変数の宣言の組み合わせ」と理解する方が適切です。

再宣言が許可される条件は以下の通りです。

  • 同じブロック内: 再宣言される変数が、元の宣言と同じブロック内で宣言されていること。
  • 同じ型: 再宣言される変数の型が、元の宣言時と同じであること。
  • 少なくとも1つの新しい変数: 複数の変数を宣言する短い変数宣言の場合、少なくとも1つの変数がそのブロック内で新しく宣言される変数であること。

この「少なくとも1つの新しい変数」という条件が重要で、これにより、既存の変数に新しい値を割り当てつつ、同時に新しい変数を導入する、というパターンが可能になります。

例:

x, y := 1, 2 // xとyを新しく宣言
x, z := 3, 4 // xは再宣言(既存のxに3を割り当て)、zは新しく宣言

このコミットは、特にこの再宣言のルールにおける「同じブロック内で以前に宣言された」という部分を明確にすることで、より厳密な解釈を促しています。

技術的詳細

このコミットの技術的な詳細は、Go言語の仕様書(doc/go_spec.html)の「短い変数宣言(Short variable declarations)」セクションにおける記述の修正にあります。

変更前は、短い変数宣言における再宣言の条件について、以下のように記述されていました。

Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared in the same block with the same type, and at least one of the non-blank variables is new.

変更後、この部分に earlier という単語が追加されました。

Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block with the same type, and at least one of the non-blank variables is new.

この earlier という単語の追加は、再宣言される変数が、現在の短い変数宣言よりも前に(コードの記述順序として)同じブロック内で宣言されている必要があることを明確にしています。これは、単に「同じブロック内」というだけでは、例えば以下のような曖昧なケースを排除するためです。

// 変更前の解釈では曖昧だった可能性のある例
a, a := 1, 2 // これは常に不正であるべき

この例では、a が同じ短い変数宣言内で二重に宣言されており、新しい変数が導入されていないため、Goの仕様上は不正です。しかし、「同じブロック内で宣言されている」という記述だけでは、このケースが明確に不正であると読み取れない可能性がありました。earlier を追加することで、再宣言の対象となる変数は、現在の宣言よりも「以前に」存在している必要があることが強調され、このような二重宣言のケースが明確に不正であると規定されます。

また、コミットでは以下の不正な例が追加されています。

a, a := 1, 2                              // illegal: double declaration of a or no new variable if a was declared elsewhere

このコメントは、a, a := 1, 2 という記述が不正である理由を二通り示しています。

  1. double declaration of a: 同じ短い変数宣言内で a が二重に宣言されているため。
  2. no new variable if a was declared elsewhere: もし a がこの短い変数宣言の前に既に宣言されていたとしても、この宣言では新しい変数が導入されていないため。

この追加された例とコメントは、earlier の追加と合わせて、短い変数宣言における再宣言のルールをより厳密かつ明確に定義し、開発者が誤ったコードを書くことを防ぐためのものです。

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

変更は doc/go_spec.html ファイルの以下の部分です。

--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
 <!--{
  "Title": "The Go Programming Language Specification",
-"Subtitle": "Version of January 7, 2013",
+"Subtitle": "Version of January 9, 2013",
  "Path": "/ref/spec"
 }-->
 
@@ -1920,7 +1920,7 @@ _, y, _ := coord(p)  // coord() returns three values; only interested in y coord
 
 <p>
 Unlike regular variable declarations, a short variable declaration may redeclare variables provided they
-were originally declared in the same block with the same type, and at
+were originally declared earlier in the same block with the same type, and at
 least one of the non-<a href=\"#Blank_identifier\">blank</a> variables is new.  As a consequence, redeclaration
 can only appear in a multi-variable short declaration.
 Redeclaration does not introduce a new
@@ -1930,6 +1930,7 @@ variable; it just assigns a new value to the original.\n <pre>\n field1, offset := nextField(str, 0)\n field2, offset := nextField(str, offset)  // redeclares offset\n+a, a := 1, 2                              // illegal: double declaration of a or no new variable if a was declared elsewhere\n </pre>\n \n <p>\n```

具体的には、以下の2点が変更されています。

1.  **仕様書のバージョン日付の更新**:
    `- "Subtitle": "Version of January 7, 2013",`
    `+ "Subtitle": "Version of January 9, 2013",`
    これは、仕様書の内容が更新されたことを示す日付の変更です。

2.  **短い変数宣言の再宣言ルールの明確化**:
    `- were originally declared in the same block with the same type, and at`
    `+ were originally declared earlier in the same block with the same type, and at`
    `"earlier"` という単語が追加されました。

3.  **不正な例の追加**:
    `+a, a := 1, 2                              // illegal: double declaration of a or no new variable if a was declared elsewhere`
    短い変数宣言の不正な使用例が追加されました。

## コアとなるコードの解説

このコミットの核心は、Go言語の仕様書における短い変数宣言の再宣言ルールをより厳密に定義した点にあります。

変更前は、「同じブロック内で宣言され、同じ型を持ち、かつ少なくとも1つの新しい(ブランクでない)変数が含まれる場合」に再宣言が許可されるとされていました。この記述は、多くのケースで正しく機能しますが、`a, a := 1, 2` のような、同じ短い変数宣言内で同じ変数を複数回宣言しようとする「コーナーケース」において、その挙動が不明確になる可能性がありました。

`earlier` という単語が追加されたことで、再宣言の対象となる変数は、**現在の短い変数宣言よりも前に**、同じブロック内で既に宣言されている必要があることが明確になりました。これにより、`a, a := 1, 2` のような、新しい変数を導入しない、あるいは同じ宣言内で同じ変数を二重に宣言するようなケースが、明確に不正であると規定されます。

追加されたコメント `// illegal: double declaration of a or no new variable if a was declared elsewhere` は、この新しいルールを補強します。

*   `double declaration of a`: これは、`a, a := 1, 2` のように、同じ短い変数宣言の左辺で同じ変数名が複数回出現する場合を指します。これは常に不正です。
*   `no new variable if a was declared elsewhere`: これは、もし `a` が既に存在していたとしても、この `a, a := 1, 2` という宣言では新しい変数が導入されていないため、再宣言の条件(「少なくとも1つの新しい変数」)を満たさないことを意味します。

この変更は、Go言語のコンパイラが短い変数宣言をどのように解釈し、エラーを報告すべきかについて、より明確な指針を与えます。結果として、開発者はより予測可能な挙動を期待でき、言語の堅牢性と一貫性が向上します。

## 関連リンク

*   Go言語の仕様書(公式): [https://go.dev/ref/spec](https://go.dev/ref/spec)
*   Go言語の短い変数宣言に関する公式ドキュメント(変更が反映された後のバージョン): [https://go.dev/ref/spec#Short_variable_declarations](https://go.dev/ref/spec#Short_variable_declarations)

## 参考にした情報源リンク

*   GitHub: golang/go commit f1cc0f44e384ff33179a2cc6d19369237cdc64cd: [https://github.com/golang/go/commit/f1cc0f44e384ff33179a2cc6d19369237cdc64cd](https://github.com/golang/go/commit/f1cc0f44e384ff33179a2cc6d19369237cdc64cd)
*   Go言語の短い変数宣言に関する一般的な解説記事(Goの基本的な挙動を理解するため)
    *   Go言語の変数宣言と初期化: [https://go.dev/doc/effective_go#declaration](https://go.dev/doc/effective_go#declaration) (Effective Goより)
*   Go言語のイシュートラッカー(`Fixes #4612` の詳細を調査したが、直接的な関連は見つからなかったため、一般的な情報源として記載): [https://github.com/golang/go/issues](https://github.com/golang/go/issues)