このドキュメントは、http://golang.org/doc/code.htmlの翻訳です。


はじめに
コミュニティ リソース
新しいパッケージの作成
Makefile
Go言語のソースファイル
プログラムのビルド
テスト
テストを必要とするパッケージの例
アーキテクチャおよびOS依存のコード

はじめに

このドキュメントでは新しいパッケージの作成方法、およびテスト方法について説明します。インストール手順に従いGo言語のインストールが済んでいることが前提となっています。

既存のパッケージに変更を加えるか、もしくは新しいパッケージの作成に取り掛かる前には必ず、あなたが何をしようとしているのかを他の人達に知らせるためにメーリングリスト宛にメールを送るようにしてください。そうすることで重複による無駄な労力が減らせるとともに、コードを書く前に仕様に関する議論をすることができます。

コミュニティ リソース

リアルタイムサポートは、Freenode IRCサーバの#go-nutsチャネルにて。

Go言語の公式ディスカッション用メーリングリストは Go Nutsにて。

バグの報告はGo issue trackerまで。

開発の状況を知りたい方は、別のメーリングリストgolang-checkinsにてGoリポジトリの個別のチェックイン情報のサマリーが受け取れます。

新しいパッケージの作成

インポートの際に使用されるパスが x/yとなるパッケージのソースコードは、慣例によってディレクトリ$GOROOT/src/pkg/x/yに格納されます。

Makefile

ソースファイルをチェックしてどれをどの順番でビルドすべきか判断するようなGo言語の仕様と合ったツールがあればよいのですが、現時点でGo言語ではGNU makeを使っています。新しいパッケージディレクトリに最初に作成するファイルは、通常は上で述べたMakefileになります。Goソースツリーで使われている標準的なMakefileとしてsrc/pkg/container/vector/Makefileを参考にしてください。

include ../../../Make.inc

TARG=container/vector
GOFILES=\
	intvector.go\
	stringvector.go\
	vector.go\

include ../../../Make.pkg

Goソースツリーの外(私的なパッケージ)での標準的なMakefileは次のようになります。

include $(GOROOT)/src/Make.inc

TARG=mypackage
GOFILES=\
	my1.go\
	my2.go\

include $(GOROOT)/src/Make.pkg

最初と最後の行では、標準的な定義とルールをincludeしています。各パッケージでは、$(GOROOT)/srcとする代わりに相対パスを使って標準Goツリーにアクセスしているので、$(GOROOT)にスペースが含まれていても正しく動作します。これはGo言語を初めて触るプログラマに役立ちます。

お使いの環境で$GOROOTを設定していないとき、この形式のmakefileを使うには、gomakeを実行する必要があります。gomakeは、GNU Makeがmakeでなくgmakeとしてインストールされたシステム上でも、それを考慮して、GNU Makeを実行します。

TARG はこのパッケージのターゲットとなるインストールパスであり、クライアントがこのパッケージをインポートするときに使う文字列です。Goツリー内では、この文字列はMakefile が置かれているディレクトリ名と同じでなければなりませんが文字列の前に$GOROOT/src/pkg/は不要です。Goツリー外では、標準Goパッケージの名前と重ならなければ好きなTARG が使用できます。一般的には、自作パッケージのグルーピングに使用しているトップレベルの名前を使います(myname/treemyname/filterなど)。自作パッケージをGoツリー外で管理するときも同様に、make installを実行すると標準インストール先である$GOROOT/pkgにパッケージのバイナリがインストールされるようにしてください。このようにすると後で探しやすくなります。

GOFILES はパッケージを作成するためにコンパイルするソースファイルのリストです。行末の文字\はリストを複数行に分割して並び替えやすくするためのものです。

Goツリー内に新しくパッケージ用ディレクトリを作成するときは、標準ビルドに組み入れるために、そのディレクトリを$GOROOT/src/pkg/Makefile 内のリストに加えてください。それでは、実行してみます。

cd $GOROOT/src/pkg
./deps.bash

これを実行するのは依存関係ファイルMake.depsを更新するためです。(all.bash またはmake.bashを実行したときには自動的に行われます。)

既存パッケージのインポートを変更したときは、$GOROOT/src/pkg/Makefileの変更は不要ですが、上のdeps.bashの実行が必要です。

Go言語のソースファイル

Makefile 内にリストされている各ソースファイルの先頭ステートメントはパッケージ名でなければなりません。またその名前はパッケージがインポートされるときに使われるデフォルトの名前であり、同一パッケージ内のすべてのファイルで同じ名前を使わなければなりません。Go言語では慣習的に、パッケージ名はインポートパスの最後の要素であり、"crypto/rot13"としてインポートされるパッケージはrot13という名前になります。

パッケージの名前は、ひとつのバイナリとしてリンクされる全てのパッケージ内でユニークとなる必要はありませんが、インポートするパス(パッケージのフルネーム)だけはユニークである必要があります。

Go言語では、ひとつのパッケージのソースファイルを一度にまとめてコンパイルするので、特別な決め事や宣言をすることなく、あるファイルから別ファイル内の定数、変数、型、関数を参照することができます。

Goコードの簡潔かつ慣用的な書き方については、このドキュメントの範囲外ですので、実践Go言語(Effective Go)をご覧ください。

プログラムのビルド

gomakeを使ってGo言語のプログラムをビルドするときは、プログラムのソースファイルと一緒にMakefileを作成します。Makefileは、さきほどのサンプルのように記述しなくてはなりませんが、次のようにMake.pkgの代わりにMake.cmdをインクルードします。

include $(GOROOT)/src/Make.inc

TARG=helloworld
GOFILES=\
	helloworld.go\

include $(GOROOT)/src/Make.cmd

gomakeを実行すると、helloworld.goがコンパイルされ、カレントディレクトリにhelloworldという名の実行ファイルが生成されます。

gomake installを実行すると、必要に応じhelloworldをビルドした後、それを$GOBINディレクトリ(デフォルトは、$GOROOT/bin/)にコピーします。

テスト

Go言語にはgotestと呼ばれる軽量のテスト用フレームワークがあります。テストを記述するには、ファイル名の後ろに_test.goが付いたファイルを作成し、そこにシグネチャfunc (t *testing.T)を持つTestXXX という名前の関数を記述します。テストフレームワークがこれらの関数をそれぞれ実行します。その関数内でt.Errort.Failといったエラー通知関数を呼び出すと、テストは失敗したと判断されます。もっと詳しい説明はgotestコマンドのドキュメント(未訳)、およびtestingパッケージのドキュメントをご覧ください。

なお、この*_test.goファイルは Makefile内のリストに記述しないでください。

テストを実行するには、make testまたはgotest を実行してください。(このふたつは同じことです) テストファイルをひとつだけ実行したいときは、たとえばone_test.goであればgotest one_test.goを実行してください。

コードの変更がパフォーマンスに影響を及ぼすようなときは、Benchmark関数(gotestコマンドドキュメントを参照)を追加したのち、gotest -test.bench=.を使って実行してください。

新しいコードをテストしてうまく動いたときが、レビューと投稿を行うタイミングです。

テストを必要とするパッケージの例

このサンプルプログラムは、Double関数という、intを引数として取り、それを2倍した値を返す関数を持つ、numbersパッケージです。これは、3つのファイルを使います。

最初は、パッケージの実装です。numbers.go:

package numbers

func Double(i int) int {
	return i * 2
}

次は、テス用のプログラムです。numbers_test.go:

package numbers

import (
	"testing"
)

type doubleTest struct {
	in, out int
}

var doubleTests = []doubleTest{
	doubleTest{1, 2},
	doubleTest{2, 4},
	doubleTest{-5, -10},
}

func TestDouble(t *testing.T) {
	for _, dt := range doubleTests {
		v := Double(dt.in)
		if v != dt.out {
			t.Errorf("Double(%d) = %d, want %d.", dt.in, v, dt.out)
		}
	}
}

最後は、Makefile:

include $(GOROOT)/src/Make.inc

TARG=numbers
GOFILES=\
	numbers.go\

include $(GOROOT)/src/Make.pkg

gomake installを実行すると、パッケージはビルドされて、$GOROOT/pkg/ディレクトリにインストールされます。(以降、システム上のどのプログラムからも利用可能になります)

gomake testの実行(もしくは、gotestコマンドの実行)により、パッケージは、numbers_test.goファイルと一緒に再ビルドされた後、TestDouble関数が実行されます。すべてのテストが成功すると、「PASS」と表示されます。実装を改変し、乗算する値を2から3に変えることで、テストが失敗したときに、どのように報告がなされるかを見ることができます。

より詳細については、gotest documentation(未訳)、およびtestingパッケージを参照ください。

アーキテクチャおよびOS依存のコード

始めに注意事項です。どのハードウェア/オペレーティングシステム上で実行されているかを知らなくてはならないパッケージはごく一部であり、大抵は言語および標準ライブラリが互換性で問題となる大部分をハンドリングしてくれています。このセクションは、三角関数の高速な計算、または異なるオペレーティングシステム上に共通のインタフェースを実装するコードのためにアセンブリ言語を使用するといったプラットフォームに依存するコードを書く必然性がある、熟練システムプログラマに向けた解説です。

このようなコードをコンパイルするには、$GOOSおよび$GOARCH環境変数を、ソースファイル名とMakefileに使用します。

例えば、次のMakefileでは、$GOOSでファイル名をパラメータ化することで、オペレーティング毎にパッケージを入れ替えています。

include $(GOROOT)/src/Make.inc

TARG=mypackage
GOFILES=\
	my.go\
	my_$(GOOS).go\

include $(GOROOT)/src/Make.pkg

OS依存のコードは、my_linux.go, my_darwin.goといった名前になります。

このようにパラメーター化する慣習に従っていれば、goinstallなどのツールは自作パッケージであってもシームレスに動作します:

my_$(GOOS).go
my_$(GOARCH).go
my_$(GOOS)_$(GOARCH).go

.s(アセンブリ)ファイルも同様です。