(GOPATH を使った) Go コードの書き方 (翻訳)

注意: これは古いバージョン (Go 1.13 より前) の Go 言語についてのドキュメントです。最新版の Go 言語を使うときはこのページをご覧ください。

イントロダクション

このドキュメントではシンプルな Go パッケージの開発を通して go ツールを紹介します。go ツールは Go パッケージやコマンドをフェッチ・ビルド・インストールするための標準的な方法です。

go ツールを使うには、コードを決められた方法で整理する必要があります。そのためこのドキュメントは注意深く読むようにしてください。Go インストールを使いこなすための一番単純な方法を説明しています。

このドキュメントと同じ内容を解説をした動画もあります (英語)。

コードの構造

概要

このコードの構造が他のプログラミング言語のものと異なる点に注意してください。多くのプログラミング言語ではプロジェクトごとにワークスペースが作成され、ワークスペースとバージョン管理レポジトリが密接な関係を持ちます。

ワークスペース

ワークスペースのトップディレクトリには次の二つのディレクトリが含まれます:

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              # パッケージのソース
    ... (レポジトリとパッケージがさらにたくさん続く) ...

このツリーで表されるワークスペースには、exampleimage という二つのレポジトリが含まれます。example レポジトリには hellooutyet という二つのコマンドと 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.Errort.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 testtesting パッケージのドキュメント を参照してください。

リモートパッケージ

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 getGOPATH によって指定される最初のワークスペースにそのパッケージを配置します (パッケージが既に存在するなら 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 Wikigodoc.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).

広告