Skip to content

Instantly share code, notes, and snippets.

@shkumagai
Last active March 30, 2023 03:54
Show Gist options
  • Save shkumagai/6069017 to your computer and use it in GitHub Desktop.
Save shkumagai/6069017 to your computer and use it in GitHub Desktop.
How to Write Go Code

Goコードの書き方

Version: Build version go 1.1.1
original:http://golang.org/doc/code.html

このドキュメントではシンプルなGoパッケージの開発を実際にやってみて、Goパッケージや コマンドをフェッチ、ビルド、およびインストールする標準的な方法である goツール を紹介 します。

goツールは、あなたのコードが指定の方法で整理されている必要があります。 このドキュメントを注意深く読んでください。Goのインストレーションを組み上げ、実行する ための最も簡単な方法を説明しています。

同様の説明が スクリーンキャスト として利用可能です。

Goツールは公開リポジトリでメンテナンスされているオープンソースコードで動作するように 設計されています。あなたのコードを公開する必要はありませんが、環境の設定方法のモデル はコードを公開してもしなくても同様に動作します。

Goコードはワークスペース内に保存する必要があります。ワークスペースは、ルートに3つの ディレクトリを持つディレクトリ階層です:

  • src はパッケージ単位(1ディレクトリ毎に1パッケージ)に整理されたGoソースファイルを、
  • pkg はパッケージオブジェクトを、そして
  • bin は実行可能なコマンドを含みます。

Goツールはソースパッケージをビルドして pkgbin ディレクトリに結果のバイナリを インストールします。

src サブディレクトリは通常、1つまたは複数のソースパッケージの開発を追跡する、 複数の(GitやMercurialのような)バージョン管理リポジトリを含んでいます。

実際のワークスペースがどのようなものかが分かるように、例を示します:

bin/
    streak                         # command executable
    todo                           # command executable
pkg/
    linux_amd64/
        code.google.com/p/goauth2/
            oauth.a                # package object
        github.com/nf/todo/
            task.a                 # package object
src/
    code.google.com/p/goauth2/
        .hg/                       # mercurial repository metadata
        oauth/
            oauth.go               # package source
            oauth_test.go          # test source
    github.com/nf/
        streak/
            .git/                  # git repository metadata
            oauth.go               # command source
            streak.go              # command source
        todo/
            .git/                  # git repository metadata
            task/
                task.go            # package source
            todo.go                # command source

このワークスペースは、2つのコマンド(streak, todo)と2つのライブラリ (oauth, task)を含む、3つのリポジトリ(goauth2, streak および todo)が含まれています。

コマンドとライブラリは異なる種類のソースパッケージからビルドされます。区別については 後で 説明します。

GOPATH 環境変数はワークスペースの場所を指定します。これは恐らくGoコードを開発する ときにだけ設定する必要がある環境変数です。

まずはじめにワークスペースのディレクトリを作成し、それに応じてGOPATHを設定します。 ワークスペースは好きな場所に配置できますが、このドキュメントでは$HOME/goを使用します。 これはGoのインストレーションと同じパスであってはいけないことに注意してください。

$ mkdir -p $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

次に、以下のGoコードを含む hello.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 コマンドをビルドし、実行可能なバイナリを提供します。その後、 ワークスペースの bin ディレクトリにそのバイナリを hello (Windows環境では hello.exe) としてインストールします。この例では、 $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 という名前のファイルを作成します。

// Package newmath is a trivial example package.
package newmath

// Sqrt returns an approximation to the square root of 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

これは出力ファイルを生成しません。ワークスペースの pkg ディレクトリ内にパッケージ オブジェクトを配置するためには、 go install を使わなければなりません。

newmathパッケージがビルドされたことを確認したあと、それを使用するために、オリジナルの ($GOPATH/src/github.com/user/hello にある) hello.go を変更します:

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              # command executable
pkg/
    linux_amd64/       # this will reflect your OS and architecture
        github.com/user/
            newmath.a  # package object
src/
    github.com/user/
        hello/
            hello.go   # command source
        newmath/
            sqrt.go    # package source

go installがnewmath.aオブジェクトを、そのソースディレクトリをそっくり映した pkg/linux_amd64 ディレクトリに配置していることに注意してください。これはgo toolの 将来の呼び出しがパッケージオブジェクトを見つけて、パッケージの不必要な再コンパイルを 避けることができるようにするためです。 linux_amd64 の部分は、クロスコンパイルを 支援するためにあり、あなたのシステムのオペレーティングシステムとアーキテクチャに 反映されます。

Goコマンド実行可能ファイルは静的にリンクされています; パッケージオブジェクトはGoの プログラムを実行するために存在する必要はありません。

Goソースファイルの最初の行は

package name

となり、 name はインポートのためのパッケージのデフォルトの名前でなければなりません。 (パッケージ内の全てのファイルは同じ名前を使用しなければなりません。)

Goの規約では、パッケージ名はインポートパスの最後の要素になります: "crypto/rot13"として インポートされるパッケージは"rot13"という名前を付ける必要があります。

実行可能コマンドは、常にパッケージ main を使わなければなりません。

パッケージ名は、単一のバイナリにリンクされている全てのパッケージの中で一意である必要は なく、ただ1つインポートパス(それらの完全なファイル名)が一意であることが要件です。

Goの命名規則について詳細を知るためには、 Effective Go を参照してください

Goはgo testコマンドと testing パッケージで構成される軽量のテストフレームワークを 持っています。

func (t *testing.T) シグネチャを持つ TestXXX という名前の関数を含んだ、 _test.go で終わる名前のファイルを作成して、テストを書きます。テストフレームワークでは そのような関数を実行します; もし関数が t.Errort.Fail のような障害関数を 呼び出した場合、そのテストは失敗したと見做されます。

以下のGoコードを含むファイル $GOPATH/src/github.com/user/newmath/sqrt_test.go を 作成してnewmathパッケージにテストを追加しましょう。

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                 # command executable
pkg/
    linux_amd64/
        code.google.com/p/go.example/
            newmath.a     # package object
        github.com/user/
            newmath.a     # package object
src/
    code.google.com/p/go.example/
        hello/
            hello.go      # command source
        newmath/
            sqrt.go       # package source
            sqrt_test.go  # test source
    github.com/user/
        hello/
            hello.go      # command source
        newmath/
            sqrt.go       # package source
            sqrt_test.go  # test source

Google Codeでホストされている hello コマンドは、同じリポジトリ内のnewmathパッケージに 依存しています。 hello.go ファイルの中のインポートは、同じインポートパス規則を使って いるので、go getコマンドは依存するパッケージも見つけてインストールすることもできます。

import "code.google.com/p/go.example/newmath"

この規則は、あなたのGoパッケージを他の人が利用可能にするための最も簡単な方法です。 Go Wikigodoc.org では外部のGoプロジェクトの一覧を提供しています。

goツールを使ったリモートリポジトリの利用に関する詳細については、 go help remote を 参照してください。

わかり易く、慣用的なGoコードを書く上でのヒントは、 Effective Go を参照してください。

言語をきちんと学習するには A tour of Go をやりましょう。

Go言語とそのライブラリやツールについての詳細な記事ひとそろいは、 ドキュメントページ を ご覧ください。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment