コードの書き方
ここでは小さなコードを書いて、実行、テストする方法を学びます。
このページはGo1.13以降の利用を前提とします。
コードの単位
コードを書き始める前に、コードの作成単位について説明します。
Goにはコードのまとまりとして、次の単位があります。
- モジュール:パッケージの集合、依存関係を含むコードの配布・バージョン管理単位
- パッケージ:同じディレクトリにあるソースファイルの集合、コードの利用単位
- ソースファイル:同じパッケージの間で共有される型・変数・定数・関数の集合、ファイル単位
具体的な構成例として、この後に説明するサンプルの構成を次に示します。
モジュールパス:example.com/user/myapp
myappディレクトリ(パッケージ:main)
├── go.mod(モジュールのバージョンを管理するファイル)
├── go.sum(利用モジュールのsum値を管理するファイル)
├── myapp.go(mainパッケージのソースファイル)
└── calcディレクトリ(パッケージ:calc)
├── calc.go(calcパッケージのソースファイル)
└── calc_test.go(calcパッケージのソースファイル)
モジュールのルートディレクトリはmyapp
ディレクトリです。
このリポジトリはモジュールexample.com/user/myapp
を含み、モジュールはmain
パッケージとcalc
パッケージを含みます。
モジュールパスはインポートパスの接頭辞として機能します。
たとえば、calc
パッケージのインポートパスはexample.com/user/myapp/calc
です。
標準ライブラリのパッケージはインポートパスにモジュールパスを含みません。
さらにモジュールパスはモジュールの場所を表します。
一般的にモジュールはGitHubやGitLabなどのインターネット上のサービスに公開します。
そのサービスのURLをモジュールパスにすることで、インターネット上にあるモジュールを簡単に利用できます。
たとえば、GitHubではgithub.com/<user>/<repo>
をモジュールパスとします。
もちろん、公開はしなくてもモジュールを作成できます。
サンプルのモジュールパスは実在しないためexample.com/user/myapp
としています。
最初のプログラム
リポジトリを作成し、Goのコードを書いて、実行する方法を説明します。
最初にリポジトリ用のディレクトリとして、myapp
ディレクトリを作成します。
それから、myapp
ディレクトリに移動し、go mod init
コマンドを実行することで現在のディレクトリがGoのモジュールであることを宣言します。
go mod init
を実行すると現在のディレクトリにgo.mod
というファイルが作成されます。
ここにはモジュールに関する情報が記録されます。
mkdir $HOME/myapp
cd myapp
# 現在のディレクトリがモジュールであることを宣言する
go mod init example.com/user/myapp
# ファイルgo.modが作成されたことを確認する
ls
次にコードを書きます。現在のディレクトリにmyapp.go
というソースファイルを作成します。ファイルは次の内容としてください。
package main
import (
"fmt"
)
// mainパッケージのmain関数はプログラムの始まりとなる場所
func main() {
/*
画面に『Hello, world』と表示する
これはコメントでプログラムの動作に影響しない
*/
fmt.Println("Hello, world.")
}
go run
コマンドを使ってコードをコンパイルし、実行します。
引数は実行対象のディレクトリを指定できます。
ここでは現在のディレクトリ(main
パッケージ)を実行するため.
を指定します。
cd $HOME/myapp
go run .
画面に次の内容が表示されます。
Hello, world
go install
コマンドを使ってコンパイルし、実行可能なバイナリファイルを出力できます。
デフォルトでは$HOME/go/bin
に出力されます(出力先は環境変数GOPATH
やGOBIN
で制御できます)。
# 実行可能なバイナリファイルを$HOME/go/binに出力
go install
# 出力した実行可能ファイルを実行
export PATH=$PATH:$(dirname $(go list -f '{{.Target}}' .))
myapp
gitを利用している場合は、ここでコミットをしましょう。
cd $HOME/myapp
git init
git add go.* *.go
git commit -m "first commit"
これでリポジトリとGoのモジュールを作成し、最初のプログラムを実行できました。
コードを整形する
続いて、コードの見た目を綺麗にする方法を説明します。
Goではコードの見た目を整形するためのツールが用意されています。 このツールのお陰で、誰が書いても同じような見た目のコードに統一できます。
先ほどのmyapp.go
を次の内容に書き換えてください。
これは、意図的に見づらいコードを書いたものです。
package main;import( "fmt");func main ( ) {
fmt.Println ( "Hello, world.")
}
次にgo fmt
を用いてこの見づらいコードを整形します。
cd $HOME/myapp
go fmt
myapp.go
が次のように整形されたことを確認します。
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, world.")
}
エディタによってはファイル保存時に自動でgo fmt
を実行する機能があります。
お使いのエディタの設定を確認しておくと良いでしょう。
これでコードの整形ができました。
他のパッケージを使う
続いて、他のパッケージを作成し、それを利用するコードを書いてみましょう。
今回は計算をするcalc
パッケージを作成します。
先ほどのリポジトリのルートディレクトリにcalc
ディレクトリを作成し、その中にcalc.go
を作成します。
cd $HOME/myapp
mkdir calc
touch calc/calc.go
calc.go
は次の内容とします。
// パッケージ名はディレクトリ名と同じにするとわかりやすい
package calc
// Add関数は2つの整数を受け取って、それを足した結果を返す。
// 他のパッケージから利用するため、関数名の1文字目を大文字にする。
func Add(x int, y int) int {
return x + y
}
Add
関数は大文字で始まるため、他のパッケージから利用できます。
あわせて、myapp.go
はAdd
関数を利用するように書き換えます。
package main
import (
"fmt"
// calcパッケージを利用する
// インポートパスは『モジュールパス』と『モジュールのサブディレクトリ』を
// 結合したもの
"example.com/user/myapp/calc"
)
func main() {
// calcパッケージのAdd関数を実行する
// 1 + 2 の結果を表示する
fmt.Println(calc.Add(1, 2))
}
go run
コマンドを使ってプログラムを実行します。
go run .
次の内容が画面に表示されます。
3
これで他のパッケージを作成し、それを利用したコードを書くことができました。
リモートモジュールを利用する
続いて、インターネット上に公開されているモジュールを利用してみましょう。 今回はGoogleが公開している『データの比較をするモジュール』を使います。
myapp.go
を次の内容に書き換えます。
import文にgithub.com/google/go-cmp/cmp
を追加しました。先述の通り、モジュールパスは公開先URLです。
実際に公開先のモジュールhttps://github.com/google/go-cmpが存在することを確認してみましょう。
package main
import (
"fmt"
"example.com/user/myapp/calc"
"github.com/google/go-cmp/cmp"
)
func main() {
// calcパッケージのAdd関数を実行する
// 1 + 2 の結果を表示する
fmt.Println(calc.Add(1, 2))
// 2つの値を比較して違いがあれば表示する
fmt.Println(cmp.Diff(1, 2))
}
go mod tidy
コマンドを使ってソースファイルのimport文を参照し、必要なモジュールをダウンロードします。
go mod tidy
cat go.mod
go.mod
とgo.sum
には使用するモジュールとしてgithub.com/google/go-cmp
の情報が追加されます。
module example.com/user/myapp
go 1.15
require github.com/google/go-cmp v0.5.2
go run
コマンドを使ってプログラムを実行します。
cd $HOME/myapp
go run .
画面には次の内容が表示されます。
3
int(
- 1,
+ 2,
)
これでリモートモジュールを利用したコードを書くことができました。
テストする
続いて、コードをテストしましょう。
Goにはあらかじめテストをするための仕組みが備わっています。
ここではcalc.go
のテストとしてcalc_test.go
を作成します。
ファイル名の末尾が_test.go
であるファイルは、テスト用のソースファイルとして扱われます。
cd $HOME/myapp
touch calc/calc_test.go
関数名がTest
で始まり、関数のシグネチャはTestXxx(t *testing.T)
である関数を作成します。
Goはこのような関数をテスト関数として実行します。
t.Error
メソッドを呼び出すと、テスト失敗とみなされます。
calc_test.go
に次の内容を書きます。
package calc
import "testing"
// テスト用の関数は関数名をTestで始める
func TestAdd(t *testing.T) {
cases := []struct {
inX, inY, want int
}{
// 次の形式で、関数の入力値と期待値をいくつか書く
// {xの値, yの値, xとyを足し算した値(期待する処理結果)}
{1, 2, 3},
{2, 3, 5},
{-1, 1, 0},
}
for _, c := range cases {
// Add関数を実行する
got := Add(c.inX, c.inY)
// Add関数の実行結果が期待値と一致することを確認する
// 不一致の場合、テストに失敗したことを通知する
if got != c.want {
t.Errorf("Add(%d, %d) == %d, want %d", c.inX, c.inY, got, c.want)
}
}
}
go test
コマンドを使ってテストを実行します。
引数にはテスト対象のパッケージパスを指定します。
./...
は現在のディレクトリとそのサブディレクトリすべてを指します。
cd $HOME/myapp
go test ./...
テストが成功すると、次の内容が画面表示されます。calc
パッケージの行がokであることを確認します。
? example.com/user/myapp [no test files]
ok example.com/user/myapp/calc 0.053s
お疲れ様でした。これでコードを書くための一連の作業を体験できました。