この記事はGo言語の公式ドキュメント" How to Write Go Code"の一部を自己学習のために翻訳したものです。
コード構成(Code organization)
全体(Overview)
- Go言語はすべてのコードを一つの「ワークスペース」で管理しています。
- ワークスペースは複数のVCSリポジトリを含んでいる
- それぞれのリポジトリは一つあるいは複数のパッケージを格納しています。
- それぞれのパッケージは単一のディレクトリ中の一つあるいは複数のGoのソースファイルから構成されています。
- パッケージのディレクトリについてのパスは
import path
を定義しています。
ワークスペース(Workspaces)
ワークスペースはルートに二つのディレクトリを持つ、ディレクトリの階層構造です。
-
src
はGoのソースファイルを格納しています。 -
bin
は実行可能なコマンドを格納しています。
go
ツールはビルドの実行およびbin
ディレクトリへのインストールを行います。
src
ディレクトリは一般的に複数の(GitやMercurialのような)バージョン管理リポジトリを含んでおり、単一あるいはそれ以上のソースパッケージの開発をトラッキングします。
ワークスペースが実際にどのようなものかを理解していただくための例がこちらです。
bin/
hello # command executable
outyet # command executable
src/
github.com/golang/example/
.git/ # Git repository metadata
hello/
hello.go # command source
outyet/
main.go # command source
main_test.go # test source
stringutil/
reverse.go # package source
reverse_test.go # test source
golang.org/x/image/
.git/ # Git repository metadata
bmp/
reader.go # package source
writer.go # package source
... (many more repositories and packages omitted) ...
上記のツリーはワークスペースが(example
とimage
の)二つのリポジトリを保持していることを示しています。
example
リポジトリは二つのコマンド(hello
とoutyet
)と一つのライブラリ(stringutil
)を保持しています。
またimage
リポジトリはbmp
パッケージといくつか別のものを保持しています。
一般的なワークスペースはいくつものパッケージとコマンドが含まれた複数のソースリポジトリを格納しています。
多くのGoのプログラマはGoのソースコードとDependenciesを単一のワークスペースに保持しています。
注釈しておくと、シンボリックリンクはファイルとディレクトリをワークスペースに関連づけるために使うべきではありません。
コマンドとライブラリは異なるソースパッケージからビルドされます。この違いに関しては後ほどお話しします。
GOPATH
環境変数(The GOPATH environment variable)
GOPATH環境変数はあなたのワークスペースの場所を明示します。
それはあなたのホームディレクトリ中のgo
と命名されているディレクトリをデフォルトに設定します、なのでUnixでは$HOME/go
、Plan 9では$home/go
、そしてWindowsでは%USERPROFILE%\go
(一般的にはC:\Users\YourName\go
)となっています。
もしあなたが異なる場所で作業したい場合、そのディレクトリのパスへGOPATHを設定する必要があります(他の共通的なセットアップはGOPATH=$HOME
へ設定することです)。
GOPATHはGoがインストールされている場所と同一にしてはいけない点に注意してください。
go env GOPATH
コマンドは現在の実際のGOPATHを表示してくれます。もし環境変数が設定されていない場合はデフォルトの場所を示してくれます。
利便性のためにワークスペースのbin
サブディレクトリをあなたのPATHに追加しましょう:
$ export PATH=$PATH:$(go env GOPATH)/bin
本ドキュメントにおけるスクリプトは簡潔さのために$(go env GOPATH)の代わりに
$GOPATH`を用います。
To make the scripts run as written if you have not set GOPATH, you can substitute $HOME/go in those commands or else run:
$ export GOPATH=$(go env GOPATH)
GOPATH環境変数にさらに学ぶためには、go help gopathを参照してください。
独自のワークスペースの場所を利用するためには、GOPATH環境変数を設定するを参照。
インボートパス(Import paths)
import path
は独自にパッケージを識別するための文字列です。パッケージのインボートパスはワークスペースあるいはリモートリポジトリの場所に対応します(後ほど説明します)。
スタンダードライブラリ由来のパッケージは"fmt"や"net/http"のように短縮されたインポートバスが与えられています。
あなたの独自のパッケージについては、将来的なスタンダードライブラリあるいは別の外部ライブラリと衝突しないようなベースパスを選択しなければいけません。
もしあなたのコードをどこかのソースリポジトリに保持したい場合、ソースリポジトリのルートをベースパスとして設定すべきです。例えばあなたがgithub.com/user
というGitHubアカウントを持っていた場合、それがあなたのベースパスとなるべきということです。
ビルドができるようになる前にリモートリポジトリにあなたのソースコードを公開する必要はないことを注釈しておきます。
これはあなたがコードをいつか公開することになることになった場合、コードを構成するのにちょうどいい習慣になります。
実際にはスタンダートライブラリやGoのエコシステムに対してパス名が独自である限り、あなたは適当なパス名を選択することができます。
github.com/user
を私たちのベースパスとして使うことにします。あなたのワークスペース内部でソースコードを保持するディレクトリを作成してください。
$ mkdir -p $GOPATH/src/github.com/user
あなたの最初のプログラム(Your first program)
簡単なプログラムのコンパイルと実行を行うために、まずパッケージパスを選択しましょう(私たちはgithub.com/user/hello
を使います)。そして対応するパッケージディレクトリをワークスペース内部に作成します。
$ mkdir $GOPATH/src/github.com/user/hello
次に以下のコードを含んだhello.go
という名前のファイルをディレクトリ内部に作成します。
package main
import "fmt"
func main() {
fmt.Println("Hello, world.")
}
今あなたはこのプログラムを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
コマンドをビルドし、実行可能なバイナリを生成します。そしてこのバイナリをワークスペースのbin
ディレクトリにhello
としてインストールします(あるいはWindowsの場合はhello.exe
として)。
私たちの例では、それは$HOME/go/bin/hello
である$GOPATH/bin/hello
となります。
go
ツールはエラーが発生した場合、アウトプットのみを表示します。そのためそれらのコマンドは正常に実行された場合何も出力を生成しません。
今あなたはコマンドラインにてフルパスを入力することで、プログラムを実行できます。
$ $GOPATH/bin/hello
Hello, world.
あるいは$GOPATH/bin
をPATHに追加していれば、バイナリ名のみを入力すれば良いです。
$ hello
Hello, world.
もしあなたがソース管理システムを利用している場合、今がリポジトリのイニシャライズ、ファイルの追加、そして最初の変更をコミットする良いタイミングでしょう。
もう一度言うと、これは任意のステップです。あなたはGoのコードを書くためにソース管理を利用する必要はありません。
あなたの最初のライブラリ(Your first library)
ライブラリを書いて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
パッケージのビルドを確認したら、それを使うようにあなたの元々のhello.go
($GOPATH/src/github.com/user/hello
にある)を変更しましょう。
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, Go!
上記のステップを踏んだ後、あなたのワークスペースはこのようになっているはずです:
bin/
hello # command executable
src/
github.com/user/
hello/
hello.go # command source
stringutil/
reverse.go # package source
パッケージ名(Package names)
第一のステートメントとして、Goのソースファイルは必ず次のようになっている必要があります。
package name
name
はインポートのためのパッケージのデフォルト名です(すべてのパッケージ中のファイルは同一のname
を使っている必要があります)。
Goの規約として、パッケージ名はインポートパスの最後の要素であるというのがあります。crypto/rot13
としてインポートされるパッケージはrot13
として命名されるべきです。
実行可能なコマンドは常にpackage main
を使わなければなりません。
パッケージ名は単一のバイナリに紐づくすべてのパッケージにおいてユニークである必要はありません。ただインポートパス(それらのフルファイル名)のみがユニークです。
Goの命名規則についてより学ぶために、効率的なGoを参照してください。
所感
Goの単一管理するワークスペースという概念は独特で面白いですね。
このドキュメントでは発展的なコードを書くわけではありませんが、基本的なGoの概念を学ぶには良いなと思いました。