導入
第5章で「パッケージ」と「大文字・小文字で公開/非公開が決まる」ことを学びました。実際のプロジェクトでは、1つのパッケージを複数のファイルに分けて書き、go.mod で依存ライブラリのバージョンまで管理します。ここでは、その一歩実務寄りの姿を見ておきましょう。
説明
Go では、同じディレクトリにある .go ファイルは、先頭の package 宣言が同じなら自動的に1つのパッケージとしてまとまります。ファイルを分けても、import し直す必要はありません。
myapp/
├── go.mod
├── main.go // package main
├── handler.go // package main(main.go と同じパッケージ)
└── util.go // package main(同上)
// main.go
package main
func main() {
result := add(1, 2) // util.go の関数がそのまま呼べる
println(result)
}
// util.go
package main
func add(a, b int) int {
return a + b
}
main.go と util.go は別ファイルですが、同じ package main なので add を import なしで呼び出せます。「1ファイル1関数」のように機能ごとにファイルを分け、見通しをよくするのが実務での定石です。
go.mod の中身は、モジュール名・Go のバージョン・依存ライブラリの一覧です。
module example.com/myapp
go 1.22
require (
github.com/google/uuid v1.6.0
github.com/stretchr/testify v1.9.0
)
requireの行が、外部ライブラリとそのバージョン(セマンティックバージョニング)です。go getでライブラリを追加すると、このrequireに自動で追記されます。- 実際にダウンロードしたコードの正確性(改ざんされていないか)を確認するためのハッシュ値が
go.sumというファイルに記録されます。go.mod/go.sumはどちらも Git にコミットして、チーム全員が同じバージョンを使えるようにします。
大きなプロジェクトでは、internal という名前のディレクトリに置いたパッケージは、そのモジュールの外から import できないというルールもあります。「社外・他プロジェクトには公開したくない実装」を隔離するのに使われる、Go 特有の仕組みです。
myapp/
├── go.mod
├── main.go
└── internal/
└── billing/
└── billing.go // myapp の外からは import できない
大文字始まりで「関数単位の公開/非公開」を決め、internal ディレクトリで「パッケージ単位の公開/非公開」を決める――この2段構えが Go のカプセル化の基本です。
このサイトは1ファイルだけを実行する学習用シミュレータのため、複数ファイル構成そのものは動かせません。実際に手元の環境(またはGo Playgroundの複数ファイルタブ)で go mod init から試してみると、感覚がつかめます。