Go言語のモジュールとパッケージ
2026/07/28

モジュール

モジュールは、1つのアプリやライブラリをまとめる単位です。go.modが置かれたフォルダとその中身全体が1つのモジュールになります。go.modファイルはgo mod initコマンドで生成することができます。サブディレクトリごとにgo mod initする必要はありません。同じgo.modの下にあるパッケージは、すべてこのモジュールに属します。

mkdir demo
cd demo
go mod init example.com/demo
module example.com/demo

go 1.26

go行は、このモジュールが想定するGo言語のバージョンです。

外部パッケージをソースコード上でimportし、go mod tidyコマンドを実行すると、外部ライブラリを自動で検知し、go.modの依存関係を自動で更新してくれます。

パッケージ

パッケージはコンパイルの単位であり、識別子の名前空間でもあります。通常、1つのディレクトリが1つのパッケージです。同じディレクトリの.goファイルには同じpackage句を書き、まとめてコンパイルします。

// greeter/greet.go
package greeter

func Hello(name string) string {
    return "hello, " + name
}
// main.go
package main

import (
    "fmt"

    "example.com/demo/greeter"
)

func main() {
    fmt.Println(greeter.Hello("Go"))
}

import

package句のあと、import宣言で外部から使用したいパッケージを読み込むことができます。

import "fmt"

()を使ってまとめてimportすることもできます。

import (
    "errors"
    myio "io"
    _ "image/png"
)

別名を付けると、パッケージ名の衝突を避けられます。myio "io"ならmyio.Readerのように使います。

importしたパッケージを使用しないとコンパイルエラーになります。使用はしないけどパッケージの初期化だけ実行したいときは_ "image/png"のようにブランクimportします。

import . "fmt"は、パッケージ名なしで識別子を取り込む書き方です。通常ならfmt.Printlnと書くところを、Printlnだけで呼べます。

import . "fmt"

func main() {
    Println("hello") // fmt.Println("hello")と同じ
}

importパスとパッケージ名

importパスは、import "..."に書く文字列です。モジュールパスにディレクトリを足したもので、どのフォルダのコードを取り込むかを指定します。パッケージ名は、取り込んだあとにコード上で使う名前です。そのディレクトリの.goファイル先頭のpackage句で決まります。

// greeter/greet.go
package greeter

func Hello(name string) string {
    return "hello, " + name
}
import "example.com/demo/greeter" // importするときはディレクトリ名

greeter.Hello("Go")               // 呼び出すときはpackage名

公開と非公開

関数や定数といった識別子の公開範囲は、名前の先頭文字で決まります。大文字で始まる名前は他パッケージから参照でき、小文字で始まる名前は同じパッケージ内だけです。

package greeter

func Hello() string { // 他パッケージから呼べる
    return hello()
}

func hello() string { // 同じパッケージ内だけ
    return "hello"
}
import "example.com/demo/greeter"

greeter.Hello()
// greeter.hello() // コンパイルエラー: 小文字は他パッケージから見えない

internalパッケージ

パスにinternalを含むパッケージは、そのinternalの親ディレクトリ以下からだけimportできます。

たとえばexample.com/demo/internal/storeは、example.com/demo/...配下からはimportできますが、別モジュールやexample.com/demoの外にあたるパスからはimportできません。公開したくない実装を内側に閉じるための仕組みです。

ドキュメントコメント

ドキュメントコメントは、トップレベルのpackage、const、var、type、funcの直前に、空行を挟まず書いたコメントです。関数内の変数や、関数の引数・戻り値名には、ドキュメントコメントはありません。

// ParseConfigは設定ファイルを読み込む。
func ParseConfig(path string) (*Config, error) {
    // ...
}

コメントと宣言のあいだに空行があると、ドキュメントにはなりません。

// このコメントはドキュメントにならない

func other() {}

constやvarをまとめたときは、グループ全体へのコメントと、各識別子の行末コメントが使えます。構造体のフィールドとインターフェースのメソッドも、型のドキュメントの一部になります。

// Statusは処理の状態です。
type Status int

const (
    Ready   Status = 1 // 準備完了
    Running Status = 2 // 実行中
)

// Serverは待ち受け設定です。
type Server struct {
    Host string // 待ち受けホスト
    Port int    // 待ち受けポート
}

init関数

パッケージ内にfunc init()を複数定義できます。initはインポートや変数の初期化のあと、自動的に実行されます。

func init() {
    log.SetFlags(log.LstdFlags)
}

パッケージの初期化順序

パッケージの初期化は次の順序です。

  1. インポートされたパッケージ(依存関係の順)
  2. パッケージレベルの変数(宣言順)
  3. init関数(ソースファイル内の出現順)

フォーマット

Go言語のソースコードは、手で細かく揃えるのではなくgofmt(パッケージ単位ならgo fmt)で機械的に整形することができます。インデントはタブ、空白の入れ方や並びも標準形に揃います。

ファイルをその場で書き換える例です。

gofmt -w main.go

パッケージ単位で揃えるときはgo fmtを使います。結果のスタイルはgofmtと同じです。

go fmt ./...

テスト

テストは、対象と同じディレクトリに_test.goで終わるファイルを置きます。書き方は2通りあり、非公開の識別子をテストできるかどうかが異なります。

同じpackage greeterで書くと、非公開の識別子も含めパッケージ内部がすべて見えます。非公開の補助関数や内部状態まで検証したいときに使います。importは不要で、同じパッケージの関数をそのまま呼べます。

// greeter/greet_test.go
package greeter

import "testing"

func TestHello(t *testing.T) {
    if Hello("Go") != "hello, Go" {
        t.Fatal("unexpected greeting")
    }
}

package greeter_testで書くと、他パッケージからの利用と同じです。importが必要で、公開されている識別のみテストできます。

// greeter/greet_ext_test.go
package greeter_test

import (
    "testing"

    "example.com/demo/greeter"
)

func TestHello(t *testing.T) {
    if greeter.Hello("Go") != "hello, Go" {
        t.Fatal("unexpected greeting")
    }
    // greeter.hello() // コンパイルエラー: 他パッケージからは見えない
}

依存の追加と利用

go getは、指定したモジュールを依存関係に追加し、ソースコードをマシン上のモジュールキャッシュへダウンロードします。モジュールキャッシュの既定の配置場所は$GOPATH/pkg/modで、複数のプロジェクト間で共有されます。プロジェクト直下にライブラリ用のディレクトリは作られず、依存関係はgo.modに記録されます。

go get rsc.io/quote

取得したパッケージをコード内で使うには、ソースファイルでimportを宣言します。

package main

import (
    "fmt"

    "rsc.io/quote"
)

func main() {
    fmt.Println(quote.Hello())
}
go run .

fmtなどの標準ライブラリはGo言語のツールチェーンに含まれているため、go getで追加する必要はなく、go.modにも記録されません。

go.modとgo.sum

依存を追加すると、go.modにrequireディレクティブが追加されます。ここに記録されるバージョンは固定値ではなく、ビルドに必要な最小バージョンです。依存先モジュールがより新しい最小バージョンを要求している場合は、すべての要求を満たすバージョンが自動で選ばれます。公開されている最新バージョンへ勝手に更新されるわけではありません。

module example.com/demo

go 1.26

require rsc.io/quote v1.5.2

依存の追加に伴い、チェックサムを記録するgo.sumも作成または更新されます。ダウンロードしたモジュールの内容が将来にわたって改ざんされていないかを検証するためのファイルです。依存関係を定義するgo.modと、その完全性を保証するgo.sumは、どちらもソースコードと一緒にGitなどのバージョン管理に含めます。

requireの行末に付く// indirectは、現在のモジュールから直接importされていない間接依存を表します。依存先モジュールが内部で利用しているモジュールや、go getで追加したもののコード上でまだimportしていないモジュールに付与されます。ソースコードで直接importして利用を始めると、この表記は自動で外れます。手動で編集する必要はなく、go getやgo mod tidyによって管理されます。

go mod tidyによる同期

go getを使わずに、先にソースコードへimportを書いてから依存を同期する方法もあります。

import "rsc.io/quote"
go mod tidy

go mod tidyは、ソースコード内のimport宣言に合わせてgo.modとgo.sumを同期します。不足している依存を追加し、コード内で使われていない依存を削除します。そのため、依存をやめるときはソースコードから対象のimportと利用箇所を削除してgo mod tidyを実行します。

バージョンの指定

依存のバージョンを指定するには、モジュールパスの末尾に@とバージョンを付けます。

go get rsc.io/[email protected]
go get rsc.io/quote@latest

@latestを指定すると、公開されている最新のリリースバージョンが選ばれます。リリースがなければv1.2.3-preのようなプレリリース、タグがなければ既定ブランチの最新コミットが選ばれます。

バージョンを省略してgo get rsc.io/quoteを実行した場合も、基本は@latestと同じです。すでに要求しているバージョンの方が新しいときだけ、手元を維持します。

どちらの場合も、go.modには解決された具体的なバージョン番号が記録されます。go.modに手動でlatestと書くことはできず、バージョンの更新はgo getで行います。

メジャーバージョンとimportパス

メジャーバージョンが2以上のモジュールは、パスの末尾に/v2や/v3のようなバージョン接尾辞が付きます。go getの引数だけでなく、コード内のimportパスにもこの接尾辞を含めます。

go get rsc.io/quote/v3@latest
import "rsc.io/quote/v3"

quote.HelloV3()

接尾辞の異なるパスは別々のモジュールです。メジャーバージョンが違えば後方互換はなく、パスが分かれているため同一プロジェクト内で同時に使えます。

go installによるバイナリの配置

go installは、mainパッケージをコンパイルし、実行可能バイナリをマシン環境へ配置するためのコマンドです。

自分のプロジェクトで作成したコマンドをビルドして配置する場合は、バージョンを指定せずに実行します。現在のモジュールの依存関係に基づいてビルドされます。

go install .

生成された実行ファイルは、GOBIN環境変数が設定されていればそのディレクトリに、未設定であれば$GOPATH/binに配置されます。パスを通しておくことで、ターミナルから直接コマンドを実行できます。

外部のCLIツールをマシンに導入する場合は、パスの末尾に@latestなどのバージョンを指定します。この形式では現在のディレクトリにあるgo.modを読み込まず、指定したバージョンで独立してビルドされます。

go install golang.org/x/tools/cmd/stringer@latest
stringer -help