パッケージ
パッケージは、同じディレクトリにあるソースファイルの集合です。
パッケージの種類
パッケージには次の種類があります。
- 標準パッケージ:Goが最初から用意しているもの(一覧は公式ドキュメントに公開)
- サードパーティパッケージ:第三者が用意したもの
- 自作パッケージ:自分で用意したもの
これまでは標準パッケージを利用してきたものの、自分のコードは1ソースファイル1パッケージによる構成でした。 ここでは自作パッケージを作成・利用するために、ソースファイル分割とパッケージ分割の方法を説明します。
ソースファイルの分割
パッケージを分ける前に、同じパッケージの中でソースファイルを分ける方法を説明します。
ソースファイルは型・定数・変数・関数で構成されています。 これらは同じパッケージに所属する他のソースファイルから参照できます。
// このファイルが所属するパッケージ
package main
// このファイルが利用するパッケージ
import (
"fmt"
)
/* ここから下は同じパッケージの他のソースファイルから参照できる */
// 型
type myint int
// 定数
const (
c1 = 10
c2 = 20
)
// 変数
var (
v1 = 1
v2 = 2
)
// 関数
func main() {
fmt.Println(v1, v2)
fmt.Println(c1, c2)
m := myint(1)
fmt.Println(m)
}
次のサンプルは定数a
を別ソースファイルに分割したものです。
main.go
とmain2.go
は同じmain
パッケージに所属しているため、main.go
からmain2.go
の定数a
を参照できます。
main.go
package main
import (
"fmt"
)
func main() {
fmt.Println(a)
}
main2.go
package main
const a = 1
同じパッケージの中で同じ識別子を使うことはできません。
先ほどのサンプルに次のソースファイルを加えると、識別子a
の重複によりコンパイルエラーとなります。
main3.go
package main
var a = 1
パッケージの初期化(init関数)
パッケージを初期化するための特別な関数として、init
関数があります。
init
関数には次の特徴があります。
main
パッケージのmain
関数より先に実行される- Goは同じ識別子を複数回宣言できないが、
init
関数は例外で複数宣言できる
次のサンプルはmain
パッケージの2箇所にinit
関数を定義したものです。
main.go
package main
import (
"fmt"
)
func init() {
fmt.Println("main.go init")
}
func main() {
fmt.Println(a)
}
main2.go
package main
import (
"fmt"
)
const a = 1
func init() {
fmt.Println("main2.go init")
}
パッケージの分割
他のパッケージを作成し、それを利用する方法は次の通りです。
- 新たにディレクトリを作成する
- 作成したディレクトリにソースファイルを作成する
- 識別子の最初の文字を大文字にする(他のパッケージからアクセス可能になる)
次のサンプルはmain
パッケージから別に作成したanother
パッケージを利用します。サンプルの中にはモジュールやgo.mod
などこれまで説明していないものが出てきますが、これらは他のページで説明します。
サンプルのファイル構成は次の通りです。ひとつのディレクトリにひとつのパッケージが対応します。理由がなければディレクトリ名とパッケージ名はあわせておくとわかりやすいです。
ルートディレクトリ (パッケージ:main)
├── go.mod (モジュールを管理するファイル)
├── example.go (mainパッケージのソースファイル)
└── anotherディレクトリ (パッケージ:another)
└── another.go (anotherパッケージのソースファイル)
go.mod
module example
example.go
package main
import (
// anotherパッケージの利用を宣言する
// インポートパスは次の2つをスラッシュで結合したもの
// ・go.modに記載のモジュールパス(example)
// ・モジュール内のサブディレクトリ(another)
"example/another"
"fmt"
)
func main() {
// anotherパッケージの定数にアクセスする
// 形式: パッケージ名.識別子
fmt.Println(another.Num)
}
another/another.go
// 新たに作成したパッケージ
package another
// 他のパッケージからアクセスするため
// 識別子の最初の文字は大文字にする
const Num = 1
これでmain
パッケージからanother
パッケージを利用できました。
別名インポート
インポートしたパッケージに別名をつけることができます。
package main
import (
// パッケージの別名を指定
f "fmt"
)
func main() {
// 別名でアクセス
f.Println("test")
}
ブランクインポート
パッケージしたインポートを参照しないことがあります。
その場合は、インポートパスの前に_
を指定します。
package main
import (
_ "fmt"
)
func main() {
// インポートしたパッケージを参照しない
return
}
ピリオドインポート
インポートパスの前に.
をつけると、パッケージ名なしでアクセスできます。
ただし、インポート元とインポート先で同名の識別子があると、インポートできないので注意してください。
package main
import (
. "fmt"
)
// インポート先と同名の識別子はNG
// const Println = 1
func main() {
// パッケージ名は省略
Println("test")
}