go: internal package
概要
個人の備忘録としてGoのinternal packageについてまとめていきます。
(2014年当時の公式情報をもとにしています)
参考
internal package概要
internal packageとはパッケージ定義の仕組みでinternalと呼ばれるパッケージの近くのパッケージのみがimportでき、その他のパッケージからはimportできないパッケージの仕組みのことです。
a mechanism for defining packages that can only be imported by nearby code, not by any other package.
参考
背景
Goのプログラムの構造として複数のパッケージでexportしたAPIを相互にやり取りすることで1つのプロジェクトを作ります。しかし、この作りだと全てのパッケージがimport可能となります。
この仕組みではライブラリやコマンドを実装する際に不用意なexportを生みます。パッケージ分割するのに十分な大きさのファイルがあったとしても、パッケージ分割するためには他パッケージからメソッドを呼び出せるようにexportする必要があり、すなわちライブラリやコマンド利用者にも関係のない内部ロジックを呼び出せてしまう状況を作ってしまいます。パッケージの可視性を制限できるようにすることでこの課題を解決できます。
パッケージ可視性の制限に関するGoのmainリポジトリで3つのモチベーション
-
Goの標準ライブラリではexportされてない重複したいくつかのコードがあります。理由は共有化するにはそれらの関数をexportしなければならないからです。
例えば、パッケージnet/httpとnet/http/httputilはパース関数をいくつか共有していて、func itoaがいくつかのパッケージにそれぞれあります。同様に、パッケージcmd/nmとcmd/objdumpは同じファイル読み取りコードが含まれています。 -
パッケージ
sc.io/x86/x86asmとrsc.io/arm/armasm中のコードのサブセットがパッケージcmd/objdumpによって参照されています。標準パッケージの一部とすることなくこれらの必要なパッケージをコピーできるようにしたいこと。 -
GoでGoのコンパイラーが実装される際、Goのメインリポジトリには存在するけど標準ライブラリではないコンパイラ用のライブラリパッケージを書く方法が必要です。
これ以外のリポジトリに取り組む開発者は似たような問題に遭遇していました。
Proposal
internalを含むパッケージのimportはinternalパッケージの親のディレクトリツリーのルートのパッケージのみがimportできるようにします。
An import of a path containing the element “internal” is disallowed if the importing code is outside the tree rooted at the parent of the “internal” directory.
例
- パッケージ
/a/b/c/internal/d/e/fのコードは/a/b/cのディレクトリルートのみからimportできます。パッケージ/a/b/gのコードからはimportできません -
$GOROOT/src/pkg/internal/xxxは標準ライブラリ($GOROOT/src/)中のその他のコードからのみimportできます -
$GOROOT/src/pkg/net/http/internalは標準ライブラリnet/httpとnet/http/*パッケージのみからimportできます -
$GOPATH/src/mypkg/internal/fooは$GOPATH/src/mypkgのコード中のみからimportできます
Discussion