公開技術情報

[English] [Japanese]

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 したパッケージを除く全てのシンボル
同一ファイル内 全てのシンボル

ここで上記のシンボルは、ファイル内の最上位スコープで定義したシンボルを指します。

ブロック内で定義したシンボルは、一般的なレキシカルスコープです。