Go のパッケージ
go の名前空間は、次の 4 つあります。
-
ユニバース
- print や panic などの go の組込み関数用の名前空間
-
パッケージ
- fmt や log など import で使用可能になる名前空間
-
ファイル
- ファイル内に閉じた名前空間
-
ブロック
- 関数や構造体など
{}
で閉じられた名前空間
- 関数や構造体など
ここでは、パッケージについて記載します。
パッケージのルール
パッケージには次のルールがあります。
- パッケージ == ディレクトリ
- パッケージは名前を持つ
- パッケージの外部に公開するシンボルは、先頭を大文字にする
これらのルールについて以降で説明します。
パッケージ == ディレクトリ
1 つのパッケージは、1つのディレクトリです。
逆に言えば、1 つのディレクトリに複数のパッケージを含めることは出来ません。
import "fmt"
など import に指定する ""
の部分には、
パッケージへの PATH を書きます。
この指定の PATH のディレクトリを検索する検索パスが、 GOROOT あるいは GOPATH です。 ここで、GOROOT は go の標準パッケージを検索するパスで、 GOPATH はサードパーティパッケージを検索するパスです。
つまり import "PATH" は、 PATH で指定されたディレクトリを GOROOT あるいは GOPATH から検索し、 発見したディレクトリ内の .go ファイルを名前空間に含める処理を行なう命令です。
パッケージは名前を持つ
パッケージは名前を持ちます。
その名前を宣言するのが package 命令です。
packege main
と書けば、そのパッケージ名が main として宣言されます。
パッケージ名には次のルールがあります。
- 1 つのディレクトリでは、1つのパッケージ名しか利用できない
- main は特別なパッケージ名
- パッケージ名はディレクトリ名に依存しない
- パッケージ名はユニークでなくて良い
1 つのディレクトリでは、1つのパッケージ名しか宣言できない
前述した通り、 1 つのディレクトリに複数のパッケージを含めることは出来ません。 また、1 つのパッケージは 1 つの名前しか持てないので、 1 つのディレクトリでは、1つのパッケージ名しか宣言できません。
main は特別なパッケージ名
go は main パッケージの main 関数を、 プログラムのエントリポイントとして処理します。
よって、ライブラリのパッケージ名は main 以外でなければなりません。
パッケージ名はディレクトリ名に依存しない
パッケージを import する際に、 そのパッケージの PATH を指定します。 しかしこの PATH は、パッケージを検索するためであって、 そのパッケージの名前とは関係ありません。
例えば import "hoge"
としてインポートしたパッケージの名前が、
hoge になるとは限りません。
import "hoge"
としてインポートしたパッケージ内で packege foo
が
宣言されていれば、そのパッケージ名は foo です。
つまり、そのパッケージのシンボルにアクセスするには、
foo.Func()
のように foo を付加します。
あくまでもパッケージ名は package で宣言した名前であって、 import のパスとは別ものです。
もちろん、ディレクトリ名とパッケージ名は一致させておいた方が分かり易いので、 ディレクトリ名を設定しておくべきです。
例えば import "foo/bar/hoge"
としてアクセスするパッケージであれば、
そのパッケージ名は hoge とするのが原則です。
パッケージ名はユニークでなくて良い
パッケージ名はユニークである必要はありません。
例えば、全てのパッケージ名が hoge あっても問題ありません。 ただし、 同じ名前のパッケージを import するとエラーします。
このエラーは、import のエイリアスを利用することで回避できます。
例えば import sage "hoge"
とすることで、
hoge のパスにあるパッケージを sage としてアクセスできます。
パッケージの外部に公開するシンボルは、先頭を大文字にする
go は、public や private などのアクセス制御をキーワードで行なうのではなく、 シンボルの先頭が大文字かどうかでパッケージ外部に公開するかどうかを制御します。
このシンボルは、関数だけでなく、構造体や構造体のメンバなども含みます。
なお、パッケージ内は大文字小文字関係なく、全てのシンボルにアクセス可能です。
ただし、ファイル内でインポートしたパッケージのシンボルは、 そのファイルに閉じています。
まとめると、次のようになります。
参照するシンボルとの関係 | アクセス可能なシンボル |
---|---|
異なるパッケージ間 | 先頭が大文字のシンボル |
同一パッケージ内のファイル間 | import したパッケージを除く全てのシンボル |
同一ファイル内 | 全てのシンボル |
ここで上記のシンボルは、ファイル内の最上位スコープで定義したシンボルを指します。
ブロック内で定義したシンボルは、一般的なレキシカルスコープです。