(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).