(GOPATH を使った) Go コードの書き方 (翻訳)
注意: これは古いバージョン (Go 1.13 より前) の Go 言語についてのドキュメントです。最新版の Go 言語を使うときはこのページをご覧ください。
イントロダクション
このドキュメントではシンプルな Go パッケージの開発を通して go ツールを紹介します。go ツールは Go パッケージやコマンドをフェッチ・ビルド・インストールするための標準的な方法です。
go ツールを使うには、コードを決められた方法で整理する必要があります。そのためこのドキュメントは注意深く読むようにしてください。Go インストールを使いこなすための一番単純な方法を説明しています。
このドキュメントと同じ内容を解説をした動画もあります (英語)。
コードの構造
概要
-
Go プログラマーは通常、全ての Go コードを一つのワークスペース (workspace) に保存します。
-
ワークスペースにはバージョン管理レポジトリ (repository) が複数含まれます (Git リポジトリなど)。
-
それぞれのレポジトリには一つ以上のパッケージ (package) が含まれます。
-
それぞれのパッケージは同じディレクトリにある一つ以上の Go ソースファイルから構成されます。
-
パッケージのディレクトリのパスは、そのパッケージのインポートパス (import path) を定めます。
このコードの構造が他のプログラミング言語のものと異なる点に注意してください。多くのプログラミング言語ではプロジェクトごとにワークスペースが作成され、ワークスペースとバージョン管理レポジトリが密接な関係を持ちます。
ワークスペース
ワークスペースのトップディレクトリには次の二つのディレクトリが含まれます:
-
src: Go ソースファイル用 -
bin: コマンドの実行可能形式用
go ツールはビルドしたバイナリを bin ディレクトリにインストールします。
src ディレクトリには通常複数のバージョン管理レポジトリ (Git, Mercurial など) が含まれ、各レポジトリは一つ以上のソースパッケージの開発を管理します。
実際のワークスペースの例を次に示します:
bin/
hello # コマンドの実行可能形式
outyet # コマンドの実行可能形式
src/
github.com/golang/example/
.git/ # Git レポジトリのメタデータ
hello/
hello.go # コマンドのソース
outyet/
main.go # コマンドのソース
main_test.go # テストのソース
stringutil/
reverse.go # パッケージのソース
reverse_test.go # テストのソース
golang.org/x/image/
.git/ # Git レポジトリのメタデータ
bmp/
reader.go # パッケージのソース
writer.go # パッケージのソース
... (レポジトリとパッケージがさらにたくさん続く) ...
このツリーで表されるワークスペースには、example と image という二つのレポジトリが含まれます。example レポジトリには hello と outyet という二つのコマンドと stringutil というライブラリが含まれ、image レポジトリには bmp などのパッケージが含まれます。
ワークスペースには通常たくさんのソースレポジトリが含まれ、レポジトリにはたくさんのパッケージとコマンドが含まれます。多くの Go プログラマーは自分の書く Go ソースコードとその依存プロジェクトの全てを単一のワークスペースに保持します。
シンボリックリンクを使ってファイルやディレクトリをワークスペースに追加してはいけない点に注意してください。
コマンドを作成するソースパッケージとライブラリを作成するソースパッケージは異なります。この区別については後で触れます。
環境変数 GOPATH
環境変数 GOPATH はワークスペースの場所を指定します。デフォルトではホームディレクトリ直下の go ディレクトリであり、Unix では $HOME/go, Plan 9 では $home/go, Windows では %USERPROFILE%\go (たいていは C:\Users\YourName\go) です。
これ以外の場所で作業をするときには自分でGOPATH を設定します (GOPATH=$HOME とすることもよくあります)。
コマンド go env GOPATH は現在の GOPATH を出力します。GOPATH が設定されていなければデフォルトのディレクトリが出力されます。
簡単のために、ワークスペースの bin サブディレクトリを PATH に追加しておきましょう:
$ export PATH=$PATH:$(go env GOPATH)/bin
このドキュメントの残りの部分では、$(go env GOPATH) を省略して $GOPATH と書くことにします。$GOPATH を設定していない状態でスクリプトを実行するときには、毎回 $HOME/go と書くか、次のコマンドを一度実行しておいてください:
$ export GOPATH=$(go env GOPATH)
環境変数 GOPATH についてもっと知りたいなら、'go help gopath' を見てください。
インポートパス
インポートパス (import path) はパッケージを曖昧さ無く特定する文字列です。パッケージのインポートパスはワークスペースあるいはリモートレポジトリ内におけるパッケージの場所を表します (リモートレポジトリについては後述します)。
標準ライブラリに含まれるパッケージは "cmt" や "net/http" といった短いインポートパスを持ちます。自分のパッケージのインポートパスを決めるときには、標準ライブラリや他の外部ライブラリが将来使う名前と衝突しないようにそのベースパスを選ぶ必要があります。
コードをどこかのソースレポジトリに保存するなら、そのソースレポジトリのルートをベースパスに使うべきです。例えば GitHub アカウント github.com/user を持っているなら、ベースパスもそれにするべきです。
コードをリモートレポジトリに公開しなくてもビルドは可能なことに注意してください。いずれ公開するかのようにコードを整理するのが良い習慣であるというだけで、実際には好きなパスを選択できます。ただし標準ライブラリやその他の Go エコシステムと名前が被ってはいけません。
ここではベースパスを github.com/user とします。ワークスペースにソースコードを入れるためのディレクトリを作りましょう:
$ mkdir -p $GOPATH/src/github.com/user
最初のプログラム
単純なプログラムをコンパイルして実行するには、まずパッケージパスを選んでその名前のパッケージディレクトリをワークスペースに作成します (この例ではパッケージパスを github.com/user/hello としました):
$ mkdir $GOPATH/src/github.com/user/hello
次にこのディレクトリ内に hello.go という名前のファイルを作成し、次の Go コードを書き込みます:
package main
import "fmt"
func main() {
fmt.Println("Hello, world.")
}
ここまでくれば、go ツールを使ってプログラムをビルド・インストールできます:
$ go install github.com/user/hello
これによって hello コマンドがシステムのどこからでも実行可能になることに注意してください。上述のコマンドを実行すると、go ツールは GOPATH で指定されるワークスペースにある github.com/user/hello パッケージを探索し、ソースコードを見つけます。
パッケージディレクトリから go install を実行する場合にはパッケージパスを省略できます:
$ cd $GOPATH/src/github.com/user/hello
$ go install
このコマンドは hello コマンドをビルドし、実行可能バイナリを生成します。その後このバイナリはワークスペースの hello (Windows では hello.exe) という名前で bin ディレクトリにインストールされます。今の例では $GOPATH/bin/hello すなわち $HOME/go/bin/hello です。
go ツールが何かを出力するのはエラーが起こったときだけなので、何も出力されなければコマンドは成功しています。
コマンドラインで完全なパスを指定すればビルドしたプログラムを実行できます:
$ $GOPATH/bin/hello
Hello, world.
また $GOPATH/bin を $PATH に追加しているので、次のようにバイナリの名前だけを入力しても問題ありません:
$ hello
Hello, world.
ソース管理システムを使っているなら、この時点でレポジトリを初期化し、ファイルを追加し、最初の変更としてコミットするのがよいでしょう。繰り返しになりますが、このステップは省略可能です: Go コードを書くときにソース管理は必須ではありません。
$ cd $GOPATH/src/github.com/user/hello
$ git init
Initialized empty Git repository in /home/user/go/src/github.com/user/hello/.git/
$ git add hello.go
$ git commit -m "initial commit"
[master (root-commit) 0b4507d] initial commit
1 file changed, 7 insertion(+)
create mode 100644 hello.go
コードをリモートレポジトリにプッシュするのは読者への練習問題とします。
最初のライブラリ
ライブラリを書いて、hello プログラムから使ってみましょう。
ここでも最初のステップはパッケージパスの選択とパッケージディレクトリの作成です (ここではパッケージパスを github.com/user/stringutil とします):
$ mkdir $GOPATH/src/github.com/user/stringutil
続いて reverse.go という名前のファイルを作り、次の内容を書き込みます:
// Package stringutil contains utility functions for working with strings.
package stringutil
// Reverse returns its argument string reversed rune-wise left to right.
func Reverse(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
このパッケージが go build でコンパイルできることを確認します:
$ go build github.com/user/stringutil
パッケージのソースディレクトリで作業しているのなら、次のコマンドで済みます:
$ go build
このコマンドを実行しても出力ファイルは生成されず、代わりにコンパイルされたパッケージがローカルのビルドキャッシュに保存されます。
stringutil パッケージがビルドできることを確認したら、このパッケージを使うよう ($GOPATH/src/github.com/user/hello にある) 先ほどの hello.go を書き換えます:
package main
import (
"fmt"
"github.com/user/stringutil"
)
func main() {
fmt.Println(stringutil.Reverse("!oG ,olleH"))
}
この hello プログラムをインストールします:
$ go install github.com/user/hello
新しいバージョンの hello を実行すると、逆になったメッセージが表示されます:
$ hello
Hello, Go!
ここまでのステップが終われば、ワークスペースは次のようになっているはずです:
bin/
hello # コマンドの実行可能形式
src/
github.com/user/
hello/
hello.go # コマンドのソース
stringutil/
reverse.go # パッケージのソース
パッケージの名前
Go ソースファイルの最初の文は次の形でなければなりません:
package NAME
ここで NAME は、このパッケージをインポートして使うパッケージがこのパッケージを指し示すために使うデフォルトの名前です (パッケージに含まれる全てのファイルは同じ NAME 持つ必要があります)。
Go の慣習では、パッケージの名前をインポートパスの最後の部分にすることになっています。例えば "crypto/rot13" とインポートされるパッケージの名前は rot13 であるべきです。
実行可能形式を生成するパッケージは package main を使わなければなりません。
あるバイナリにリンクされるパッケージに同じ名前を持つものがあっても構いません。異なる必要があるのはインポートパス (の完全パス) だけです。
Go の命名規則について詳しくは Effective Go を見てください。
テスト
Go は軽量なテストフレームワークを持ちます。このフレームワークは go test コマンドと testing パッケージからなります。
テストは ..._test.go という名前のファイルに TestXXX という名前の関数として書きます。この関数は func (t *testing.T) というシグネチャを持たなければなりません。テストフレームワークはこの形をした関数を全て実行し、t.Error や t.Fail などの関数が呼ばれたらテストが失敗したと判断します。
stringutil パッケージにテストを追加してみましょう。次のコードを書き込んだファイル $GOPATH/src/github.com/user/stringutil/reverse_test.go を作成します:
package stringutil
import "testing"
func TestReverse(t *testing.T) {
cases := []struct {
in, want string
}{
{"Hello, world", "dlrow ,olleH"},
{"Hello, 世界", "界世 ,olleH"},
{"", ""},
}
for _, c := range cases {
got := Reverse(c.in)
if got != c.want {
t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want)
}
}
}
go test でテストを実行します:
$ go test github.com/user/stringutil
ok github.com/user/stringutil 0.165s
今までと同様に、go ツールをパッケージディレクトリから実行している場合にはパッケージパスを省略できます:
$ go test
ok github.com/user/stringutil 0.165s
詳しくは go help test や testing パッケージのドキュメント を参照してください。
リモートパッケージ
Git や Mercurial などのバージョン管理システムからパッケージのソースコードを取得する方法をインポートパスに埋め込むことができます。go ツールはこの機能を使ってリモートレポジトリからパッケージを自動的に取得します。例えばこのドキュメントで説明されるパッケージは Git レポジトリ github.com/golang/example として Github でホストされており、このレポジトリ URL をパッケージのインポートパスに含めておけば、go get がフェッチ・ビルド・インストールを自動で行います。
$ go get github.com/golang/example/hello
$ $GOPATH/bin/hello
Hello, Go examples!
指定したパッケージがワークスペースに存在しない場合、go get は GOPATH によって指定される最初のワークスペースにそのパッケージを配置します (パッケージが既に存在するなら go get はリモートのフェッチをスキップし、go install と同じ処理を行います)。
go get コマンドを実行し終わると、ワークスペースのディレクトリツリーは次のようになります:
bin/
hello # コマンドの実行可能形式
src/
github.com/golang/example/
.git/ # Git レポジトリのメタデータ
hello/
hello.go # コマンドのソース
stringutil/
reverse.go # パッケージのソース
reverse_test.go # テストのソース
github.com/user/
hello/
hello.go # コマンドのソース
stringutil/
reverse.go # パッケージのソース
reverse_test.go # テストのソース
Github でホストされる hello コマンドは、同じレポジトリの stringutil パッケージに依存しています。hello.go が依存するパッケージのインポートパスも同じ規則に従って指定されているので、go get コマンドはその依存先のパッケージについても特定・インストールを行います。
import "github.com/golang/example/stringutil"
この規則は Go パッケージを他人から利用可能にする一番簡単な方法です。Go Wiki と godoc.org には外部 Go プロジェクトのリストがあります。
go ツールによるリモートレポジトリの利用について詳しくは go help importpath を見てください。
次は?
golang-announce メーリングリストを購読すれば、Go の新しい安定版のリリースの通知を受け取ることができます。
Go らしい明確なコードを書くための秘訣については Effective Go を見てください。
Go 言語をしっかりと理解したいなら A Tour of Go をお勧めします。
ドキュメントページ には Go 言語やそのライブラリ・ツールに関する詳細な解説記事があります。
Attribution
Portions of this page are reproduced from work created and shared by Google and used according to terms described in the Creative Commons 4.0 Attribution License.
The original source page is How to Write Go Code (with GOPATH).