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