はじめに

この文書は、モジュール内でのシンプルなGoパッケージの開発を示し、Goモジュール、パッケージ、コマンドを取得、ビルド、インストールするための標準的な方法であるgo toolを紹介します。

コードの整理

Goプログラムはパッケージに整理されています。パッケージは、同じディレクトリ内のソースファイルのコレクションであり、一緒にコンパイルされます。1つのソースファイルで定義された関数、型、変数、および定数は、同じパッケージ内の他のすべてのソースファイルから見えるようになります。

リポジトリは1つ以上のモジュールを含みます。モジュールは、関連するGoパッケージのコレクションであり、一緒にリリースされます。Goリポジトリは通常、リポジトリのルートにある1つのモジュールのみを含みます。そこにあるgo.modという名前のファイルは、モジュールパスを宣言します:モジュール内のすべてのパッケージのインポートパスプレフィックスです。モジュールは、そのgo.modファイルを含むディレクトリ内のパッケージと、そのディレクトリのサブディレクトリを含み、次のgo.modファイルを含む別のサブディレクトリまで続きます(あれば)。

コードをリモートリポジトリに公開する前にビルドする必要はないことに注意してください。モジュールは、リポジトリに属さずにローカルに定義できます。ただし、いつか公開するつもりでコードを整理することは良い習慣です。

各モジュールのパスは、そのパッケージのインポートパスプレフィックスとして機能するだけでなく、goコマンドがそれをダウンロードする場所を示します。たとえば、モジュールgolang.org/x/toolsをダウンロードするには、goコマンドがhttps://golang.org/x/toolsによって示されるリポジトリを参照します(詳細は[https://golang.org/cmd/go/#hdr-Remote_import_paths]を参照)。

インポートパスは、パッケージをインポートするために使用される文字列です。パッケージのインポートパスは、そのモジュール内のサブディレクトリと結合されたモジュールパスです。たとえば、モジュールgithub.com/google/go-cmpは、ディレクトリcmp/にあるパッケージを含みます。そのパッケージのインポートパスはgithub.com/google/go-cmp/cmpです。標準ライブラリのパッケージにはモジュールパスプレフィックスがありません。

最初のプログラム

シンプルなプログラムをコンパイルして実行するには、まずモジュールパスを選択します(example/user/helloを使用します)し、それを宣言するgo.modファイルを作成します:

  1. $ mkdir hello # Alternatively, clone it if it already exists in version control.
  2. $ cd hello
  3. $ go mod init example/user/hello
  4. go: creating new go.mod: module example/user/hello
  5. $ cat go.mod
  6. module example/user/hello
  7. go 1.16
  8. $

Goソースファイルの最初のステートメントはpackage nameでなければなりません。実行可能なコマンドは常にpackage mainを使用する必要があります。

次に、そのディレクトリ内にhello.goという名前のファイルを作成し、次のGoコードを含めます:

  1. package main
  2. import "fmt"
  3. func main() {
  4. fmt.Println("Hello, world.")
  5. }

これで、goツールを使用してそのプログラムをビルドしてインストールできます:

  1. $ go install example/user/hello
  2. $

このコマンドはhelloコマンドをビルドし、実行可能なバイナリを生成します。その後、そのバイナリを$HOME/go/bin/hello(またはWindowsの場合は%USERPROFILE%\go\bin\hello.exe)としてインストールします。

インストールディレクトリはGOPATHおよびGOBIN 環境変数によって制御されます。GOBINが設定されている場合、バイナリはそのディレクトリにインストールされます。GOPATHが設定されている場合、バイナリはbinリストの最初のディレクトリのGOPATHサブディレクトリにインストールされます。それ以外の場合、バイナリはデフォルトのGOPATHbinサブディレクトリにインストールされます($HOME/goまたは%USERPROFILE%\go)。

go envコマンドを使用して、将来のgoコマンドのために環境変数のデフォルト値をポータブルに設定できます:

  1. $ go env -w GOBIN=/somewhere/else/bin
  2. $

go env -wによって以前に設定された変数を解除するには、go env -uを使用します:

  1. $ go env -u GOBIN
  2. $

go installのようなコマンドは、現在の作業ディレクトリを含むモジュールのコンテキスト内で適用されます。作業ディレクトリがexample/user/helloモジュール内にない場合、go installは失敗する可能性があります。

便利なことに、goコマンドは作業ディレクトリに対して相対的なパスを受け入れ、他のパスが指定されていない場合は現在の作業ディレクトリ内のパッケージをデフォルトとして使用します。したがって、作業ディレクトリ内では、次のコマンドはすべて同等です:

  1. $ go install example/user/hello
  1. $ go install .
  1. $ go install

次に、プログラムを実行して動作することを確認しましょう。さらに便利なことに、バイナリを簡単に実行できるようにインストールディレクトリをPATHに追加します:

  1. # Windowsユーザーは/wiki/SettingGOPATHを参照してください
  2. # %PATH%を設定するために。
  3. $ export PATH=$PATH:$(dirname $(go list -f '{{.Target}}' .))
  4. $ hello
  5. こんにちは、世界。
  6. $

ソース管理システムを使用している場合、今がリポジトリを初期化し、ファイルを追加し、最初の変更をコミットする良いタイミングです。このステップはオプションです:Goコードを書くためにソース管理を使用する必要はありません。

  1. $ git init
  2. Initialized empty Git repository in /home/user/hello/.git/
  3. $ git add go.mod hello.go
  4. $ git commit -m "initial commit"
  5. [master (root-commit) 0b4507d] initial commit
  6. 1 file changed, 7 insertion(+)
  7. create mode 100644 go.mod hello.go
  8. $

goコマンドは、対応するHTTPS URLを要求し、HTMLレスポンスに埋め込まれたメタデータを読み取ることによって、指定されたモジュールパスを含むリポジトリを見つけます(go help importpathを参照)。多くのホスティングサービスは、Goコードを含むリポジトリのためにそのメタデータをすでに提供しているため、モジュールを他の人が使用できるようにする最も簡単な方法は、通常、そのモジュールパスをリポジトリのURLと一致させることです。

モジュールからパッケージをインポートする

  1. ``````bash
  2. // Package morestrings implements additional functions to manipulate UTF-8
  3. // encoded strings, beyond what is provided in the standard "strings" package.
  4. package morestrings
  5. // ReverseRunes returns its argument string reversed rune-wise left to right.
  6. func ReverseRunes(s string) string {
  7. r := []rune(s)
  8. for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
  9. r[i], r[j] = r[j], r[i]
  10. }
  11. return string(r)
  12. }
  13. `

私たちのReverseRunes関数は大文字で始まるため、エクスポートされたものであり、私たちのmorestringsパッケージをインポートする他のパッケージで使用できます。

go buildを使用してパッケージがコンパイルされることを確認しましょう:

  1. $ cd $HOME/hello/morestrings
  2. $ go build
  3. $

これにより出力ファイルは生成されません。代わりに、コンパイルされたパッケージはローカルビルドキャッシュに保存されます。

  1. ``````bash
  2. package main
  3. import (
  4. "fmt"
  5. "example/user/hello/morestrings"
  6. )
  7. func main() {
  8. fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
  9. }
  10. `
  1. ``````bash
  2. $ go install example/user/hello
  3. `

プログラムの新しいバージョンを実行すると、新しい逆さまのメッセージが表示されるはずです:

  1. $ hello
  2. Hello, Go!

リモートモジュールからパッケージをインポートする

インポートパスは、GitやMercurialなどのリビジョン管理システムを使用してパッケージのソースコードを取得する方法を説明できます。goツールは、この特性を使用してリモートリポジトリからパッケージを自動的に取得します。たとえば、プログラムでgithub.com/google/go-cmp/cmpを使用するには:

  1. package main
  2. import (
  3. "fmt"
  4. "example/user/hello/morestrings"
  5. "github.com/google/go-cmp/cmp"
  6. )
  7. func main() {
  8. fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
  9. fmt.Println(cmp.Diff("Hello World", "Hello Go"))
  10. }

外部モジュールに依存関係があるため、そのモジュールをダウンロードし、go.modファイルにそのバージョンを記録する必要があります。go mod tidyコマンドは、インポートされたパッケージの不足しているモジュール要件を追加し、もはや使用されていないモジュールの要件を削除します。

  1. $ go mod tidy
  2. go: finding module for package github.com/google/go-cmp/cmp
  3. go: found github.com/google/go-cmp/cmp in github.com/google/go-cmp v0.5.4
  4. $ go install example/user/hello
  5. $ hello
  6. Hello, Go!
  7. string(
  8. - "Hello World",
  9. + "Hello Go",
  10. )
  11. $ cat go.mod
  12. module example/user/hello
  13. go 1.16
  14. require github.com/google/go-cmp v0.5.4
  15. $

モジュールの依存関係は、GOPATH環境変数によって示されるディレクトリのpkg/modサブディレクトリに自動的にダウンロードされます。特定のバージョンのモジュールのダウンロードされた内容は、そのバージョンをrequireする他のすべてのモジュールで共有されるため、goコマンドはそれらのファイルとディレクトリを読み取り専用としてマークします。すべてのダウンロードされたモジュールを削除するには、-modcacheフラグをgo cleanに渡すことができます:

  1. $ go clean -modcache
  2. $

テスト

Goには、go testコマンドとtestingパッケージで構成された軽量のテストフレームワークがあります。

テストは、_test.goで終わる名前のファイルを作成し、TestXXXという名前のfunc (t *testing.T)シグネチャを持つ関数を含めることによって書きます。テストフレームワークは、そのような関数をそれぞれ実行します。関数がt.Errort.Failのような失敗関数を呼び出すと、テストは失敗したと見なされます。

  1. ``````bash
  2. package morestrings
  3. import "testing"
  4. func TestReverseRunes(t *testing.T) {
  5. cases := []struct {
  6. in, want string
  7. }{
  8. {"Hello, world", "dlrow ,olleH"},
  9. {"Hello, 世界", "界世 ,olleH"},
  10. {"", ""},
  11. }
  12. for _, c := range cases {
  13. got := ReverseRunes(c.in)
  14. if got != c.want {
  15. t.Errorf("ReverseRunes(%q) == %q, want %q", c.in, got, c.want)
  16. }
  17. }
  18. }
  19. `

次に、go testでテストを実行します:

  1. $ cd $HOME/hello/morestrings
  2. $ go test
  3. PASS
  4. ok example/user/hello/morestrings 0.165s
  5. $

go help testを実行し、テストパッケージのドキュメントを参照して詳細を確認してください。

次は何ですか

golang-announceメーリングリストに登録して、新しい安定版のGoがリリースされたときに通知を受け取ります。

明確で慣用的なGoコードを書くためのヒントについては、Effective Goを参照してください。

言語を正しく学ぶために、A Tour of Goを受けてください。

Go言語とそのライブラリおよびツールに関する詳細な記事のセットについては、ドキュメントページを訪れてください。

ヘルプを得る

リアルタイムのヘルプが必要な場合は、コミュニティ運営のgophers Slackサーバーで役立つゴファーに尋ねてください(こちらから招待を取得)。

Go言語の議論のための公式メーリングリストはGo Nutsです。

バグを報告するには、Go issue trackerを使用してください。