このドキュメントでは簡単なGoパッケージの開発の説明、goツール、Goパッケージとコマンドの標準的なフェッチ・ビルド・インストールの方法を紹介しています。
goツールの利用に際しては、コードを特定の方法で構成する必要があります。このドキュメントを注意深く読みましょう。最も簡単にGoをインストールし、使い始める方法を説明しています。
同様の説明をスクリーンキャストで見ることができます。
goツールは、公開レポジトリでメンテナンスされているオープンソースコードを扱うことを想定して設計されています。実際にコードを公開する必要はありませんが、公開する場合もしない場合も同じ方法で環境の設定を行うことができます。
Goコードはワークスペース内に置いておく必要があります。ワークスペースはルートに以下の3つのディレクトリを持つディレクトリ階層です。
srcはパッケージに構成された(1ディレクトリに1パッケージ)Goのソースファイルを含み、
pkgはパッケージオブジェクトを含み、
binは実行形式コマンドを含みます。
goツールはソースパッケージをビルドし、その結果生成されるバイナリをpkgおよびbinにインストールします。
srcサブディレクトリは一般的に1つ以上のソースパッケージの開発を追跡するバージョンコントロールレポジトリ(Git、Mercurialなど)を複数内包します。
実際にワークスペースがどのようになっているか把握していただくために、次の例をご覧ください。
bin/
streak # コマンド実行形式ファイル
todo # コマンド実行形式ファイル
pkg/
linux_amd64/
code.google.com/p/goauth2/
oauth.a # パッケージオブジェクト
github.com/nf/todo/
task.a # パッケージオブジェクト
src/
code.google.com/p/goauth2/
.hg/ # mercurialレポジトリメタデータ
oauth/
oauth.go # パッケージソース
oauth_test.go # テストソース
github.com/nf/
streak/
.git/ # gitレポジトリメタデータ
oauth.go # コマンドソース
streak.go # コマンドソース
todo/
.git/ # gitレポジトリメタデータ
task/
task.go # パッケージソース
todo.go # コマンドソース
このワークスペースには2つのコマンド(streak and todo)と2つのライブラリ(oauth and task)から成る3つのレポジトリ(goauth2、streak、todo)が入っています。
コマンド、ライブラリは異なる種類のソースパッケージからビルドされます。この区別は以降で議論します。
GOPATH環境変数
GOPATH環境変数はワークスペースの場所を示してします。これがGoコードを開発する際に設定が必要な唯一の環境変数のはずです。
始めるにあたっては、ワークスペースディレクトリを作成し、適宜GOPATHをセットしてください。ワークスペースはどこでも好きな場所に置いてよいですが、このドキュメントでは$HOME/goとして説明しています。Goをインストールしたパスを指定してはいけないことを注意してください。
$ mkdir $HOME/go $ export GOPATH=$HOME/go
利便性向上のため、以下のようにワークスペースのbinサブディレクトリをPATHに追加してください。
$ export PATH=$PATH:$GOPATH/bin
標準ライブラリのパッケージは、"fmt"や"net/http"のように短いパスを与えられています。自分で作ったパッケージについては、将来追加されるライブラリやその他の外部ライブラリと衝突しないであろうベースパスを選ぶ必要があります。
コードをどこかのソースレポジトリに置く場合は、ベースパスとしてソースレポジトリのルートを利用する必要があります。例えば、github.com/userにあるGitHubアカウントを利用している場合には、これがベースパスとなります。
ビルドができる状態になる前にコードをリモートレポジトリに公開する必要はないことに留意してください。いつの日にか公開することを見越してコードを構成することはよい行いです。実質的には、標準ライブラリや大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.Printf("Hello, world.\n")
}
これで以下のようにgoツールでプログラムをビルドし、インストールできるようになります。
$ go install github.com/user/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, 1 insertion(+) create mode 100644 hello.go
リモートレポジトリへのコードのプッシュの方法は、読者の皆さんへの演習課題として残しておきます。
ライブラリを書いて、それをhelloプログラムで利用しましょう。
ここでも、最初のステップはパッケージパスを選び(ここではgithub.com/user/newmathとします)、以下のようにパッケージディレクトリを作成することです。
$ mkdir $GOPATH/src/github.com/user/newmath
次に、このディレクトリにsqrt.goという名前のファイルを作成し、以下の内容を記述します。
// newmathパッケージはちょっとしたサンプルパッケージです。
package newmath
// Sqrtはxの平方根の近似値を返します。
func Sqrt(x float64) float64 {
z := 1.0
for i := 0; i < 1000; i++ {
z -= (z*z - x) / (2 * z)
}
return z
}
そして、go buildでパッケージがコンパイルできることをテストします。
$ go build github.com/user/newmath
もしくは、パッケージのソースディレクトリで作業している場合には、単に以下のようにします。
$ go build
このコマンドはファイルの出力を行いません。ファイルを出力するには、go installを用いる必要があります。これにより、ワークスペースのpkgディレクトリにパッケージオブジェクトが生成されます。
newmathパッケージがビルドされたことを確認してから、元のhello.go($GOPATH/src/github.com/user/helloにある)を以下のように修正してこのパッケージを利用するようにします。
package main
import (
"fmt"
"github.com/user/newmath"
)
func main() {
fmt.Printf("Hello, world. Sqrt(2) = %v\n", newmath.Sqrt(2))
}
goツールがパッケージやバイナリをインストールする際には必ず、それらが持つすべての依存関係がインストールされます。ですので以下のようにhelloプログラムをインストールする場合には、
$ go install github.com/user/hello
newmathが同時に自動でインストールされます。
この新しいバージョンのプログラムを実行すると、以下のように何らかの数値が出力されることを確認できるはずです。
$ hello Hello, world. Sqrt(2) = 1.414213562373095
上記のステップを行うと、ワークスペースは以下のような状態になっているはずです。
bin/
hello # コマンド実行形式ファイル
pkg/
linux_amd64/ # ここはOSとアーキテクチャ名が反映されます
github.com/user/
newmath.a # パッケージオブジェクト
src/
github.com/user/
hello/
hello.go # コマンドソース
newmath/
sqrt.go # パッケージソース
go installを実行すると、newmath.aオブジェクトがpkg/linux_amd64の中にソースディレクトリと同じ階層で置かれます。これは、今後のgoツールの呼び出しの際、既存のパッケージオブジェクトを検索することで不必要なパッケージの再コンパイルを避けるようにするためです。linux_amd64の部分はクロスコンパイルを可能にするためにあり、利用しているオペレーティングシステムとアーキテクチャの名前が反映されます。
Goのコマンド実行形式ファイルは静的リンクされており、Goプログラムの実行にパッケージオブジェクトは必要ありません。
Goソースファイルの最初のステートメントは以下のようでなければなりません。
package name
nameの部分にはインポートするパッケージのデフォルト名が入ります。(パッケージ内のすべてのファイルで同じnameを利用します。)
Goの規則ではパッケージ名はインポートパスの最後の要素となります。例えば、"crypto/rot13"というパッケージをインポートする場合は、rot13とします。
実行形式ファイルのコマンドは常にpackage mainとする必要があります。
パッケージ名は、ある1つのバイナリにリンクされたすべてのパッケージを通じて一意である必要はありません。インポートパス(完全ファイル名)のみ一意である必要があります。
Goの命名規則についてさらに詳しく学びたい場合は、Effective Goをご覧ください。
Goはgo testコマンドとtestingパッケージで構成される軽量なテストフレームワークを提供します。
テストを書くには、_test.goで終わる名前のファイルを作成し、func (t *testing.T)というシグネチャのTestXXXという名前の関数を作成します。テストフレームワークはこれらの関数を一つ一つ実行し、t.Errorやt.Failといったフェイル関数が呼ばれると、テストが失敗したとみなします。
newmathパッケージのテストを追加しましょう。$GOPATH/src/github.com/user/newmath/sqrt_test.goというファイルを作成し、以下のGoコードを記述してください。
package newmath
import "testing"
func TestSqrt(t *testing.T) {
const in, out = 4, 2
if x := Sqrt(in); x != out {
t.Errorf("Sqrt(%v) = %v, want %v", in, x, out)
}
}
そして、go testでテストを実行しましょう。
$ go test github.com/user/newmath ok github.com/user/newmath 0.165s
いつもどおり、goツールをパッケージのディレクトリで実行する場合は、パッケージのパスを省略できます。
$ go test ok github.com/user/newmath 0.165s
さらに詳しい情報については、go help testを実行し、testingパッケージドキュメントをご覧ください。
GitやMercurialといったリビジョン管理システムを利用したパッケージのソースコードを利用する場合、インポートパスにはどのリビジョン管理システムから取得するかを記述するようにします。goはこのプロパティを利用してリモートレポジトリからパッケージを自動的にフェッチします。例えば、このドキュメントに記述されている例はGoogle Codeにホストされているcode.google.com/p/go.example Mercurialレポジトリにも収録されています。パッケージインポートパスにレポジトリのURLが含まれている場合は、以下のようにgo getで自動的にフェッチ、ビルド、インストールができます。
$ go get code.google.com/p/go.example/hello $ $GOPATH/bin/hello Hello, world. Sqrt(2) = 1.414213562373095
指定されたパッケージがワークスペースに存在しない場合、go getはGOPATHで最初に指定されているワークスペース内に配置します。(パッケージがすでに存在する場合、go getはリモートからのフェッチをスキップし、go installと同じように振る舞います。)
上記のgo getコマンドを発行すると、ワークスペースのディレクトリツリーは以下のようになります。
bin/
hello # コマンド実行形式ファイル
pkg/
linux_amd64/
code.google.com/p/go.example/
newmath.a # パッケージオブジェクト
github.com/user/
newmath.a # パッケージオブジェクト
src/
code.google.com/p/go.example/
hello/
hello.go # コマンドソース
newmath/
sqrt.go # パッケージソース
sqrt_test.go # テストソース
github.com/user/
hello/
hello.go # コマンドソース
newmath/
sqrt.go # パッケージソース
sqrt_test.go # テストソース
Google Codeにホストされているhelloは同じレポジトリ内のnewmathパッケージに依存しています。hello.goファイル内のインポートには同じインポートパスの規則を用います。そのため、go getコマンドは依存するパッケージも同様に場所の特定・インストールをすることができます。
import "code.google.com/p/go.example/newmath"
この規則により、自分で作ったGoパッケージを他の人が非常に容易に使えるようになります。Go Wikiやgodoc.orgに外部のGoプロジェクトの一覧があります。
goツールでリモートレポジトリを利用する際のさらに詳しい情報は、go help importpathをご覧ください。
Goの新しい安定バージョンのリリース通知を受け取るにはgolang-announceメーリングリストを購読しましょう。
きれいで慣用的なGoコードを書くためのティップスはEffective Goをご覧ください。
きちんと言語を学ぶにはA Tour of Goを利用しましょう。
Go言語とライブラリ、ツールに関するさらに詳細な記事についてはdocumentation pageをご覧ください。
リアルタイムヘルプについては、Freenode IRCサーバの#go-nutsで協力的なGopher達に質問してください。
Go言語のディスカッションのためのオフィシャルメーリングリストはGo Nutsです。
バグのレポートにはGo issue trackerを利用してください。