Goは、そのシンプルさと効率性から、大きな人気を博しているプログラミング言語です。大規模なアプリケーションの構築に最適なGoの特徴の1つに、モジュールのサポートがあります。
Go言語におけるモジュールとは、複数のGoパッケージをまとめて管理するための仕組みのことです。パッケージは、ファイルシステム内の1つのディレクトリとして表すことができましたが、モジュールによって、開発者は依存関係を構造的かつ効率的に管理することができます。
Goでモジュールを作成するのは簡単です。
最初のステップは、モジュールのための新しいディレクトリを作成することです。このディレクトリには、モジュールに関連するすべてのコードファイルが含まれます。ディレクトリの名前は自由につけることができますが、モジュールが何をするのかがわかるような名前をつけるとよいでしょう。
このチュートリアルでは、packerというモジュールを作成し、簡単な挨拶関数を作成します。まずはpackerというrootディレクトリを作成し、そのディレクトリ内に移動しましょう。
mkdir packer
cd packer
次に、"go mod init"コマンドを使ってモジュールを初期化する必要があります。このコマンドは、モジュールのディレクトリに新しい"go.mod"ファイルを作成し、モジュールの依存関係やバージョン情報をトラッキングします。
go mod init example.com/packer
ここで指定したモジュール名は、現在のディレクトリに対応したパッケージをモジュールとして公開した時のパスになり、そのモジュールをダウンロードする場所を示すことになります。例えば、ここで指定したexample.com/packerモジュールを、Goコマンドを用いてダウンロードした場合には、http://example.com/packerで示される場所からモジュールをダウンロードすることになります。
つまり、packerパッケージをexample.com/packerモジュールとして公開した場合には、packerパッケージをhttp://example.com/packerからダウンロードし、その後packerパッケージとしてインポートする形になります。
Note: モジュールはhttp://moduleNameとなるような場所からダウンロードされることが前提であるため、モジュール名には基本的にGitHubのレポジトリを指定する場合が多いです。
このようにモジュールを初期化すると、新たにgo.modファイルが作成されます。go.modファイルは、Goモジュールのパスを書いておくファイルのことです。最初は以下のような記述がされています。
module example.com/packer
// このモジュールのGoのバージョン
go 1.18
モジュールを作成したら、その中にローカルパッケージを作成することができます。パッケージとは、同じパッケージ名を共有するGoのソースファイルの集まりのことでした。この例では、packerモジュールの中にnumberというパッケージを作成することにします。
ローカルパッケージを作成するには、パッケージ名のディレクトリを作成し、そこにGoのソースファイルを追加する必要があります。以下のコマンドラインを順に実行します。
cd packer
mkdir number
cd number
touch prime.go
以下は、ローカルパッケージの構造の例です。
packer
├── number
│ └── prime.go
├── go.mod
└── main.go
上記の構造では、numberディレクトリにprime.goファイルがあり、素数に関連するコードが含まれています。このパッケージは、packer/numberというパッケージ名で、モジュール内の他のGoファイルにインポートすることができます。
prime.goのファイルには、以下のコードが書かれているとしましょう。
package number
func IsPrime(n int) bool {
for i := 2; i <= n/2; i++ {
if n%i == 0 {
return false
}
}
return n > 1
}
numberはpackerモジュール内のローカルパッケージで、数字に関するコード、特に数字が素数かどうかをチェックする関数を含むprime.goファイルを含んでいます。
Goでは、パッケージからエクスポートされた関数や型の名前は、大文字で始めるのが慣例となっています。この例では、IsPrime関数が大文字で始まっていますが、これはnumberパッケージの外部で使用されることを意図しており、それをインポートする他のパッケージにエクスポートされているためです。もしこの関数がnumberパッケージの中でのみ使用されるものであれば、小文字で始めることができます。
ローカルパッケージを使用するには、コードにインポートする必要があります。ここでは、main.goファイルでnumberパッケージを使用する例を示します。
package main
import (
"fmt"
"packer/number"
)
func main() {
fmt.Println(number.IsPrime(7)) // true
}
ローカルパッケージと標準パッケージの文字列が同じ名前である場合、パッケージのエイリアスを使用することで名前の衝突を解決することができます。パッケージエイリアスを使うには、標準パッケージをエイリアスでインポートすることで、コード内で2つのパッケージを区別することができます。
package main
import (
"fmt"
s "strings" // 標準パッケージの文字列のエイリアス
"mypackage/strings" // 同名のローカルパッケージ
)
func main() {
// 標準パッケージの文字列を別名で使用する
fmt.Println(s.ToLower("GOLANG")) // golang
// ローカルパッケージの文字列を使用する
fmt.Println(strings.Reverse("GOLANG")) // GNALOG
}
上記のコードでは、標準パッケージのstringsをエイリアスsでインポートし、標準パッケージのToLower関数を使用しています。また、同じ名前のローカルパッケージmypackage/stringsをインポートして、そこからReverse関数を使用しています。