[インデックス 18255] ファイルの概要
このコミットは、Go言語の仕様書である doc/go_spec.html
ファイルに対する変更です。具体的には、Go言語における「ドットインポート(.
import)」の挙動に関する記述を明確化し、その解釈の曖昧さを解消することを目的としています。
コミット
commit 227fe5f64e22d98e62e4e5165bffc3d6f8ec80b9
Author: Rob Pike <r@golang.org>
Date: Tue Jan 14 15:16:01 2014 -0800
spec: tighten the wording around . imports
Make it clear that if you do a . import, you cannot use a qualified identifier.
R=gri
CC=golang-codereviews
https://golang.org/cl/52390043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/227fe5f64e22d98e62e4e5165bffc3d6f8ec80b9
元コミット内容
spec: tighten the wording around . imports
Make it clear that if you do a . import, you cannot use a qualified identifier.
R=gri
CC=golang-codereviews
https://golang.org/cl/52390043
変更の背景
Go言語には、パッケージをインポートする際にいくつかの方法があります。通常は import "package_name"
のように記述し、そのパッケージの公開された識別子(関数、変数、型など)にアクセスする際には package_name.Identifier
のように「修飾識別子(qualified identifier)」を使用します。
しかし、Goには「ドットインポート(.
import)」という特殊なインポート形式も存在します。これは import . "package_name"
のように記述され、インポートされたパッケージの公開された識別子を、修飾子なしで直接現在のパッケージのスコープで利用できるようにするものです。例えば、import . "fmt"
とすると、fmt.Println
ではなく Println
と直接呼び出すことができます。
このドットインポートの挙動について、Go言語の仕様書における記述が曖昧であったため、開発者の間で誤解や混乱が生じる可能性がありました。特に、ドットインポートを行った場合に、修飾識別子(例: fmt.Println
)も引き続き使用できるのか、それとも修飾子なしでのアクセスのみが許可されるのか、という点が不明確でした。
このコミットは、この曖昧さを解消し、ドットインポートが使用された場合には修飾識別子を使用できないことを明確にするために行われました。これにより、Go言語の仕様がより厳密になり、コンパイラの挙動と開発者の期待との間に齟齬が生じることを防ぎます。
前提知識の解説
Go言語のパッケージとインポート
Go言語は、コードをパッケージという単位で整理します。パッケージは関連する機能の集まりであり、他のパッケージから利用されることを想定しています。他のパッケージの機能を利用するためには、そのパッケージをインポートする必要があります。
Goのインポートには主に以下の3つの形式があります。
-
標準インポート:
import "package_name"
最も一般的な形式です。インポートされたパッケージの公開された識別子には、package_name.Identifier
のようにパッケージ名をプレフィックスとして付けてアクセスします。 例:import "fmt"
の場合、fmt.Println("Hello")
-
エイリアスインポート:
import alias_name "package_name"
パッケージに別名(エイリアス)を付けてインポートする形式です。パッケージ名が長い場合や、名前の衝突を避ける場合などに使用されます。 例:import f "fmt"
の場合、f.Println("Hello")
-
ドットインポート(
.
import):import . "package_name"
この形式でインポートすると、インポートされたパッケージの公開された識別子が、現在のパッケージのスコープに直接導入されます。これにより、パッケージ名をプレフィックスとして付けずに、識別子を直接使用できるようになります。 例:import . "fmt"
の場合、Println("Hello")
-
ブランクインポート(
_
import):import _ "package_name"
パッケージをインポートするものの、そのパッケージの公開された識別子を現在のパッケージから直接利用しない場合に用います。主に、インポートされたパッケージのinit()
関数が実行されるという「副作用」を利用する目的で使用されます。例えば、データベースドライバの登録などに使われます。
修飾識別子 (Qualified Identifier)
Go言語において、修飾識別子とは、パッケージ名とそれに続く識別子(関数名、変数名、型名など)をドットで結合した形式の識別子を指します。例えば、fmt.Println
における fmt
がパッケージ名、Println
が識別子であり、これ全体が修飾識別子です。これは、どのパッケージのどの識別子を参照しているのかを明確にするための標準的な方法です。
ドットインポートの文脈では、この修飾識別子の使用が制限されるという点が重要になります。
技術的詳細
このコミットの技術的な詳細は、Go言語の公式仕様書である doc/go_spec.html
の記述変更に集約されます。変更前は、ドットインポートに関する記述が「...can be accessed without a qualifier.(修飾子なしでアクセスできる)」となっていました。この表現は、修飾子なしでのアクセスが可能であることを示唆する一方で、修飾子付きでのアクセスが不可能であるとは明示していませんでした。
このコミットでは、この部分の記述を「...and must be accessed without a qualifier.(そして修飾子なしでアクセスされなければならない)」に変更しています。
この変更の意図は以下の通りです。
- 明確化: ドットインポートを使用した場合、そのパッケージの識別子には修飾子を付けてアクセスすることはできない、というルールを明確にしています。これにより、コンパイラの実装と開発者の理解が一致するようになります。
- 一貫性: Go言語の設計思想として、コードの曖昧さを排除し、一貫性のある挙動を保証することが重視されます。この変更は、その原則に沿ったものです。
- コンパイルエラーの誘発: 変更後の仕様では、ドットインポートされたパッケージの識別子を修飾子付きで参照しようとすると、コンパイルエラーが発生するようになります。これにより、開発者は意図しない挙動を早期に発見し、修正することができます。
例えば、import . "fmt"
と記述した場合、変更前は Println("Hello")
と fmt.Println("Hello")
の両方が許容されるかのような誤解が生じる可能性がありましたが、変更後は Println("Hello")
のみが正しく、fmt.Println("Hello")
はコンパイルエラーとなります。
この変更は、Go言語の構文解析器やコンパイラの実装に直接的な影響を与えるものではなく、あくまで言語仕様の記述を厳密にすることで、Goプログラムの挙動に関する開発者の理解を統一し、将来的な混乱を防ぐためのものです。
コアとなるコードの変更箇所
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
<!--{
"Title": "The Go Programming Language Specification",
- "Subtitle": "Version of Jan 2, 2014",
+ "Subtitle": "Version of Jan 14, 2014",
"Path": "/ref/spec"
}-->
@@ -5669,7 +5669,7 @@ If the PackageName is omitted, it defaults to the identifier specified in the
If an explicit period (<code>.</code>) appears instead of a name, all the
package\'s exported identifiers declared in that package\'s
<a href=\"#Blocks\">package block</a> will be declared in the importing source
-file\'s file block and can be accessed without a qualifier.\n+file\'s file block and must be accessed without a qualifier.\n </p>\
\n <p>\
@@ -5693,7 +5693,7 @@ Assume we have compiled a package containing the package clause
<code>package math</code>, which exports function <code>Sin</code>, and
installed the compiled package in the file identified by
<code>\"lib/math\"</code>.\n-This table illustrates how <code>Sin</code> may be accessed in files\n+This table illustrates how <code>Sin</code> is accessed in files\n that import the package after the\n various types of import declaration.\n </p>\
コアとなるコードの解説
このコミットでは、doc/go_spec.html
ファイル内の2箇所が変更されています。
-
仕様書のバージョン日付の更新:
- "Subtitle": "Version of Jan 2, 2014", + "Subtitle": "Version of Jan 14, 2014",
これは、仕様書の内容が更新されたことに伴い、そのバージョン日付を「2014年1月2日版」から「2014年1月14日版」に更新したものです。これはドキュメントのメタデータに関する変更であり、直接的な言語仕様の変更ではありませんが、変更が適用された日付を示す重要な情報です。
-
ドットインポートに関する記述の変更:
-file\'s file block and can be accessed without a qualifier. +file\'s file block and must be accessed without a qualifier.
これがこのコミットの核心となる変更です。 変更前:
can be accessed without a qualifier.
(修飾子なしでアクセスできる) 変更後:must be accessed without a qualifier.
(修飾子なしでアクセスされなければならない)can be accessed
は「〜できる」という可能性を示唆する表現であり、修飾子付きでのアクセスも許容されるかのような解釈の余地がありました。 一方、must be accessed
は「〜されなければならない」という義務や制約を示す強い表現です。これにより、ドットインポートされた識別子には、必ず修飾子なしでアクセスしなければならず、修飾子付きでのアクセスは許可されないことが明確に規定されました。 -
例示テーブルの記述の変更:
-This table illustrates how <code>Sin</code> may be accessed in files +This table illustrates how <code>Sin</code> is accessed in files
変更前:
may be accessed
(アクセスされうる) 変更後:is accessed
(アクセスされる)これも同様に、曖昧な表現からより断定的な表現への変更です。ドットインポートの挙動が明確化されたため、例示テーブルにおけるアクセス方法も「〜されうる」という可能性ではなく、「〜される」という確定的なものとして記述されるようになりました。これは、仕様の厳密化に伴う表現の調整です。
これらの変更により、Go言語のドットインポートの挙動に関する仕様がより厳密かつ明確になり、開発者がGoコードを記述する際の誤解が減り、コンパイラの挙動との一貫性が保たれるようになりました。
関連リンク
- Go Code Review: https://golang.org/cl/52390043
参考にした情報源リンク
- Go言語のインポートについて:
- https://boldlygo.tech/posts/2023/08/28/go-import-mechanisms/
- https://go101.org/article/package-import-and-initialization.html
- https://medium.com/@prashant.nair2000/understanding-go-imports-a-comprehensive-guide-321212121212
- https://www.tutorialspoint.com/go/go_packages.htm
- https://www.geeksforgeeks.org/go-packages/
- Go言語の仕様書に関する情報: