本文へスキップ
BecomeCoder

Goコース · 第7章 パッケージと標準ライブラリ · レッスン25

パッケージ設計の実践 ― 複数ファイルとモジュール管理

ローカル実施

導入

第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.goutil.go は別ファイルですが、同じ package main なので addimport なしで呼び出せます。「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.modgo.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 から試してみると、感覚がつかめます。