パッケージ
Goプログラムはパッケージをリンクすることで構築されます。 パッケージは1つまたは複数のソースファイルから構成され、それらのファイルは定数、型、変数、関数を宣言し、 それらは同じパッケージのすべてのファイルからアクセス可能です。 これらの要素はエクスポートされ、別のパッケージで使用できます。
ソースファイルの構成
各ソースファイルは、そのファイルが属するパッケージを定義するパッケージ句で始まり、 使用したいパッケージの内容を宣言するインポート宣言(空の場合もあります)が続き、 その後に関数、型、変数、定数の宣言(空の場合もあります)が続きます。
SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
パッケージ句
パッケージ句は各ソースファイルの先頭に配置され、そのファイルが属するパッケージを定義します。
PackageClause = "package" PackageName .
PackageName = identifier .
PackageNameはブランク識別子であってはなりません。
package math
同じPackageNameを共有するファイルのセットがパッケージの実装を形成します。 実装によっては、パッケージのすべてのソースファイルが同じディレクトリに存在することが要求される場合があります。
インポート宣言
インポート宣言は、その宣言を含むソースファイルがインポートされたパッケージの機能に依存していることを示し (§プログラムの初期化と実行)、 そのパッケージのエクスポートされた識別子へのアクセスを可能にします。 インポートはアクセスに使用される識別子(PackageName)と、インポートするパッケージを指定するImportPathを指定します。
ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
ImportSpec = [ "." | PackageName ] ImportPath .
ImportPath = string_lit .
PackageNameはインポート元のソースファイル内でパッケージのエクスポートされた識別子にアクセスするための
修飾識別子で使用されます。
これはファイルブロックで宣言されます。
PackageNameが省略された場合、インポートされたパッケージのパッケージ句で指定された識別子がデフォルトとなります。
名前の代わりにピリオド(.
)が明示的に表示されている場合、
そのパッケージのパッケージブロックで宣言されたパッケージのエクスポートされたすべての識別子が、
インポート元のソースファイルのファイルブロックで宣言され、修飾子なしでアクセスする必要があります。
ImportPathの解釈は実装依存ですが、 通常はコンパイルされたパッケージの完全なファイル名のサブストリングであり、 インストールされたパッケージのリポジトリに対する相対パスである場合があります。
実装の制限: コンパイラはImportPathを、
UnicodeのL、M、N、P、S一般カテゴリ(スペースなしのグラフィック文字)に
属する文字のみを使用した空でない文字列に制限し、
!"#$%&'()*,:;<=>?[\]^
{|}`の文字およびUnicodeの置換文字U+FFFDを除外することができます。
パッケージ句package math
を含む、関数Sin
をエクスポートするコンパイル済みパッケージが、
"lib/math"
というファイルにインストールされているとします。
この表は、様々な種類のインポート宣言後にそのパッケージをインポートするファイルで、
Sin
にどのようにアクセスするかを示しています。
インポート宣言 Sinのローカル名
import "lib/math" math.Sin
import m "lib/math" m.Sin
import . "lib/math" Sin
インポート宣言は、インポートする側とされる側のパッケージ間の依存関係を宣言します。 パッケージが自分自身を直接的または間接的にインポートすることは違法であり、 エクスポートされた識別子を参照せずにパッケージを直接インポートすることも違法です。 パッケージをその副作用(初期化)のためだけにインポートするには、 明示的なパッケージ名としてブランク識別子を使用します:
import _ "lib/math"
パッケージの例
以下は、並行素数ふるいを実装する完全なGoパッケージです。
package main
import "fmt"
// 'ch'チャネルに2, 3, 4, ...の数列を送信
func generate(ch chan<- int) {
for i := 2; ; i++ {
ch <- i // 'i'を'ch'チャネルに送信
}
}
// 'src'チャネルから'dst'チャネルに値をコピーし、
// 'prime'で割り切れるものを除去
func filter(src <-chan int, dst chan<- int, prime int) {
for i := range src { // 'src'から受信した値でループ
if i%prime != 0 {
dst <- i // 'i'を'dst'チャネルに送信
}
}
}
// 素数ふるい: フィルタープロセスをデイジーチェーンで連結
func sieve() {
ch := make(chan int) // 新しいチャネルを作成
go generate(ch) // generate()をサブプロセスとして開始
for {
prime := <-ch
fmt.Print(prime, "\n")
ch1 := make(chan int)
go filter(ch, ch1, prime)
ch = ch1
}
}
func main() {
sieve()
}