パッケージ(Packages)- Golang learning step 1-7
- 公開日
- カテゴリ:LearnTheBasics
- タグ:Golang,roadmap.sh,学習メモ
roadmap.sh > Go > Learn the Basics > Packages の学習を進めていきます。
※ 学習メモとしての記録ですが、後にこのセクションを学ぶ道しるべとなるよう、ですます調で記載しています。
contents
- 開発環境
- パッケージ(Packages)
- パッケージの役割
- パッケージの作成方法
- パッケージのインポート
- パッケージの公開
- 標準ライブラリのパッケージ
- パッケージ管理ツール(go modules)
- モジュールの命名
- パッケージのドキュメント生成(go doc)
開発環境
- チップ: Apple M2 Pro
- OS: macOS Sonoma
- go version: go1.23.2 darwin/arm64
パッケージ(Packages)
Go のパッケージは、Go におけるコードの整理と再利用のための基本的な単位です。パッケージは、関連する関数、型、変数、定数をまとめて管理し、他のコードからそれらを使いやすくする仕組みです。
- [official] How to Manage External Dependencies in Go
- [article] How to create a package in Go
パッケージの役割
Go のパッケージは、コードをモジュール化し、関数や変数のスコープを管理するために使われます。大規模なプロジェクトでは、複数のパッケージを使用することで、コードの可読性や保守性を向上させます。
- 関数や変数を機能ごとに分けてパッケージにまとめることで、プロジェクトを論理的に分割できます。(コードの整理)
- Go ではパッケージごとに名前空間が異なるため、同じ名前の関数や変数を別のパッケージで使うことができます。(名前の衝突を防ぐ)
- パッケージは一度作成すると、他のプロジェクトでも簡単にインポートして再利用できます。(再利用可能)
パッケージの作成方法
パッケージは、ソースファイルの先頭に package キーワードで定義されます。たとえば、my_math パッケージを作成する場合、以下のように宣言します。
// myproject/my_math/my_math.go
package my_math
func Add(a int, b int) int {
return a + b
}
この my_math パッケージには、Add 関数が含まれており、my_math パッケージをインポートする他のファイルから利用可能です。
パッケージのインポート
他のパッケージを使用するには、import 文を使います。標準ライブラリや外部パッケージをインポートする際も、同じ手法で行います。以下は、標準ライブラリの fmt と、ユーザー定義の my_math パッケージをインポートする例です。
// myproject/main.go
package main
import (
"fmt"
"myproject/my_math" // 自分のプロジェクト内のパッケージ
)
func main() {
result := my_math.Add(3, 4)
fmt.Println(result)
// => 7
}
パッケージの公開
Go では、パッケージ内の関数や変数が大文字で始まる場合にのみ、他のパッケージからアクセスできます。たとえば、Add という関数は公開されますが、subtract という関数は同じパッケージ内でのみ使えます。
package my_math
// 公開される関数
func Add(a int, b int) int {
return a + b
}
// 非公開の関数
func subtract(a int, b int) int {
return a - b
}
標準ライブラリのパッケージ
Go には非常に多くの標準パッケージが用意されており、以下はよく使われるパッケージの一部です。
- fmt: 標準出力や文字列フォーマットに使います。
- strings: 文字列操作に便利な関数が含まれています。
- io, os: ファイルの入出力処理やシステム操作を行います。
- net/http: HTTPサーバーやクライアントを扱うためのパッケージです。
- time: 日付や時刻を扱うための関数が含まれています。
標準ライブラリは、pkg.go.dev から検索できます。
パッケージ管理ツール(go modules)
Go のパッケージ管理は、かつて GOPATH という概念に依存していましたが、現在(Go 1.11 以降)では go modules が標準となっており、go.mod ファイルを使って、依存関係の管理が行われます。
go mod init コマンドでプロジェクトをモジュール化し、依存パッケージを管理できます。
go mod init myproject
# => go: creating new go.mod: module myproject
# go: to add module requirements and sums:
# go mod tidy
go mod init を実行すると、現在のディレクトリに go.mod というファイルが生成されます。このファイルは、Go モジュールのプロジェクトを管理するための設定ファイルです。go.mod には、以下のような基本情報が記載されます。
module myproject
go 1.23.2
- module myproject: これはモジュール名を表します。myproject がモジュール名として設定されますが、通常これはリポジトリの URL やプロジェクトの名前になります(例: github.com/user/myproject)。
- go 1.23.2: プロジェクトが使用する Go のバージョンが指定されます。go mod init を実行した環境で使用している Go のバージョンが自動的に挿入されます。
モジュールの初期化と設定
go mod init コマンドを実行することで、現在のディレクトリがモジュールとして扱われます。これにより、プロジェクト内のコードは Go Modules の仕組みを使って依存関係を管理できるようになります。
モジュール化されると、プロジェクトは従来の GOPATH から独立し、プロジェクトディレクトリのどこにでも配置できます。(Go 1.11 以降、GOPATH の制約から解放されました)
Go では、モジュールはパッケージの集合体として機能します。モジュール化により、プロジェクト内のパッケージの依存関係を適切に管理し、外部パッケージのインポートも効率的に行えるようになります。
依存関係の管理
go mod init で生成された go.mod ファイルは、プロジェクトが依存する外部パッケージ(モジュール)を記録します。たとえば、外部ライブラリをインポートして使用した場合、go ツールが自動的に依存関係を解決し、go.mod にその情報が追加されます。
次に go get コマンドなどを実行すると、そのパッケージが自動的にダウンロードされ、go.mod に依存パッケージが以下のように追加されます。
go get github.com/gin-gonic/gin
# github.com/gin-gonic/gin パッケージとその依存パッケージがダウンロードされる
module myproject
go 1.23.2
require github.com/gin-gonic/gin v1.7.4
go.mod に依存する外部パッケージとそのバージョンが require セクションに記載されます。たとえば、ここでは github.com/gin-gonic/gin というパッケージのバージョン v1.7.4 が依存として追加されています。
また、依存パッケージの具体的なバージョン情報や、ソースの取得先の情報などは go.sum という別のファイルに管理されます。
go.sum ファイルの例:
github.com/gin-gonic/gin v1.7.4 h1:checksum...
github.com/gin-gonic/gin v1.7.4/go.mod h1:checksum...
# その他依存パッケージのバージョンやチェックサムも含まれる
コードにパッケージをインポートして利用
パッケージが追加されたので、プロジェクトのコード内で github.com/gin-gonic/gin パッケージをインポートして使用できます。main.go ファイルを作成し、簡単な Gin サーバーを実装してみましょう。
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello, world!",
})
})
err := r.Run() // デフォルトで :8080 ポートで実行
if err != nil {
return
}
}
コードを実行して、Gin が正しくインポートされて動作するか確認します。
go run main.go
ブラウザで http://localhost:8080
にアクセスすると、以下のような JSON レスポンスが表示されます。
{
"message": "Hello, world!"
}
これで、外部パッケージ github.com/gin-gonic/gin が依存として追加され、プロジェクト内で使用できるようになりました。
依存関係の整理・最適化(go mod tidy)
go mod tidy コマンドは、Go Modules の依存関係を整理・最適化するためのコマンドです。このコマンドを実行することで、go.mod と go.sum ファイルが最新の状態に保たれ、不要な依存関係が削除され、必要な依存関係がすべて追加されます。
具体的な役割:
- 不要な依存関係を削除
- 以前にインポートされていたけれども、現在はプロジェクト内で使われていないパッケージが go.mod から削除される。
- 例えば、ある外部ライブラリをインポートしていたが、そのライブラリのコードを削除した場合、依存関係だけが go.mod に残ることがある。このような不要な依存関係を整理できる。
- 必要な依存関係を追加
- プロジェクトのソースコード内で新たに使用されたパッケージが、まだ go.mod に登録されていない場合、自動的に追加される。
- 例えば、新しいパッケージを使用したけれども、go get コマンドを実行していない場合、このコマンドを使うことでそのパッケージの依存関係が解決される。
- go.sum の更新
- go.sum ファイルには、go.mod に記載された各パッケージの正しいバージョンとそのチェックサム(整合性を保つための値)が記録されている。
- go mod tidy を実行すると、最新の依存関係に基づいて go.sum が更新され、不要なエントリが削除され、必要なエントリが追加される。
モジュールの命名
モジュールパスの形式
モジュールパスは、モジュール(プロジェクトやライブラリ)の一意な名前です。 通常は次の形式をとります。
<接頭辞>/<説明的なテキスト>
接頭辞
接頭辞は、モジュールがどこから来たか(起源)を示す部分です。これにより、Goツールがそのモジュールのソースコードをどこで見つけられるかが分かります。
例えば、GitHub のリポジトリからモジュールを提供する場合、次のような形式にします。
github.com/<プロジェクト名>/
公開するモジュールの場合、リポジトリの場所が他の人にも分かるように接頭辞を設定します。
コントロールできる名前を選ぶ
自分だけが使う非公開モジュールやリポジトリ名を使わない場合には、他人と名前がかぶらない接頭辞を選びます。例えば、widgets や utilities のような一般的な名前は避け、他の人が使わないことを確認できる名前にする必要があります。
説明的なテキスト
接頭辞の後に続く部分は、プロジェクトの名前や機能を表す「説明的なテキスト」です。このテキストはモジュールが何をするものかを示します。
具体的な命名例
公開されているモジュールの例
もし GitHub にプロジェクトを公開しているなら、次のようにモジュールパスを設定します
github.com/example/myproject
公開についての詳細は「モジュールの開発と公開」を参照。
非公開で他の人と名前が衝突しないようにする場合
自分のプロジェクト用の特定の接頭辞を作り、次のように設定します。
myorg.com/internal/mytool
パッケージのドキュメント生成(go doc)
go doc は、Go のコードから自動的にドキュメントを生成するためのツールと規約のことです。これはGoの重要な機能の一つで、コードの可読性と保守性を高めるのに役立ちます。
ドキュメントの書き方
関数、型、パッケージの直前にコメントを書くことで、そのコメントがドキュメントとして扱われます。
パッケージレベルのコメントは、パッケージ宣言の直前に書きます。
関数や型のコメントは、その定義の直前に書きます。
myproject/mathutils/mathutils.go
// Package mathutils は数学的操作のためのユーティリティ関数を提供します。
package mathutils
// Add は2つの整数の和を返します。
// 2つのint型のパラメータを受け取り、その和を返します。
func Add(a, b int) int {
return a + b
}
// Multiply は2つの整数の積を返します。
// 2つのint型のパラメータを受け取り、その積を返します。
func Multiply(a, b int) int {
return a * b
}
特徴
- コードと一緒にドキュメントを管理できるため、コードの変更に合わせてドキュメントも更新しやすくなる。
- 標準的なフォーマットで書かれるため、一貫性のあるドキュメントを作成できる。
- godoc コマンドを使用して、ターミナルで直接ドキュメントを閲覧できる
godoc コマンドの使用
- go doc <パッケージ名>: パッケージのドキュメントを表示
- go doc <パッケージ名>.<関数名>: 特定の関数のドキュメントを表示
% go doc mathutils
# package mathutils // import "myproject/mathutils"
#
# Package mathutils は数学的操作のためのユーティリティ関数を提供します。
#
# func Add(a, b int) int
# func Multiply(a, b int) int
% go doc mathutils.Add
# package mathutils // import "myproject/mathutils"
#
# func Add(a, b int) int
# Add は2つの整数の和を返します。 2つのint型のパラメータを受け取り、その和を返します。
まとめ
- Go のパッケージは、コードの整理と再利用を促進する基本単位であり、関数や変数を論理的に分割して管理できる。
- パッケージを使うことで、名前の衝突を避け、再利用性の高いコードを書くことが可能。
- パッケージの公開・非公開は関数名や変数名の大文字・小文字によって制御される。
- 標準ライブラリには、よく使われる機能を提供する便利なパッケージが多数用意されている。
- Go Modules を使って依存関係を簡単に管理でき、GOPATH に依存せずにプロジェクトを整理できる。
- go mod tidy コマンドで、依存パッケージの整理と最適化が可能。
- go doc を使えば、自動的にドキュメントを生成し、コードの可読性や保守性を向上させることができる。
- パッケージやモジュールは論理的かつ一貫した命名規則に従って管理され、外部との依存関係も適切に設定される。
[Next] Step 1-8: 関数(Functions)