パッケージ(Packages)- Golang learning step 1-7

公開
注意最終更新から 2 年以上経過しています。最新の情報もあわせてご確認ください。

roadmap.sh > Go > Learn the Basics > Packages の学習を進めていきます。

学習箇所

※ 学習メモとしての記録ですが、後にこのセクションを学ぶ道しるべとなるよう、ですます調で記載しています。

開発環境

  • チップ: Apple M2 Pro
  • OS: macOS Sonoma
  • go version: go1.23.2 darwin/arm64

パッケージ(Packages)

Go のパッケージは、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 ファイルが最新の状態に保たれ、不要な依存関係が削除され、必要な依存関係がすべて追加されます。

具体的な役割:

  1. 不要な依存関係を削除
    • 以前にインポートされていたけれども、現在はプロジェクト内で使われていないパッケージが go.mod から削除される。
    • 例えば、ある外部ライブラリをインポートしていたが、そのライブラリのコードを削除した場合、依存関係だけが go.mod に残ることがある。このような不要な依存関係を整理できる。
  2. 必要な依存関係を追加
    • プロジェクトのソースコード内で新たに使用されたパッケージが、まだ go.mod に登録されていない場合、自動的に追加される。
    • 例えば、新しいパッケージを使用したけれども、go get コマンドを実行していない場合、このコマンドを使うことでそのパッケージの依存関係が解決される。
  3. 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 を使えば、自動的にドキュメントを生成し、コードの可読性や保守性を向上させることができる。
  • パッケージやモジュールは論理的かつ一貫した命名規則に従って管理され、外部との依存関係も適切に設定される。
Ritolabo