go fmt でコードを整形しよう

go fmt your code by Andrew Gerrand

はじめに

Gofmt はGoのソースコードを自動的に整形するツールです。

Gofmtされたコードには次のような特徴があります。

  • 書きやすい:コードを書いている最中に、些細な整形上の懸念を気にする必要がありません。

  • 読みやすい:すべてのコードが同じように見えるので、他人の整形スタイルを頭の中で自分が理解できる形に変換する必要がありません。

  • 保守しやすい:ソースへの機械的な変更が、ファイルの整形とは無関係な変更を引き起こすことがありません。diffには本当の変更だけが表示されます。

  • 意見の対立が起きない:スペースの入れ方や波括弧の位置について、二度と議論する必要がありません!

コードを整形する

私たちは最近、世の中に存在するGoパッケージの調査を行い、その約70%がgofmtのルールに従って整形されていることがわかりました。これは予想していたよりも多く、gofmtを使ってくれているすべての人のおかげですが、このギャップを埋められればさらに素晴らしいことです。

コードを整形するには、gofmtツールを直接使えます。

gofmt -w yourcode.go

あるいは、“go fmt” コマンドを使うこともできます。

go fmt path/to/your/package

コードを正規のスタイルに保ちやすくするために、Goのリポジトリにはエディタやバージョン管理システム向けのフックが含まれていて、コードに対してgofmtを簡単に実行できるようになっています。

Vimユーザー向けには、Vim plugin for Go に、現在のバッファに対してgofmtを実行する :Fmt コマンドが含まれています。

emacsユーザー向けには、go-mode.elgofmt-before-save フックを提供しています。これは .emacs ファイルに次の行を追加することでインストールできます。

(add-hook 'before-save-hook #'gofmt-before-save)

EclipseやSublime Textのユーザー向けには、GoClipseGoSublime のプロジェクトが、それぞれのエディタにgofmt機能を追加しています。

そしてGitを愛用する人向けには、misc/git/pre-commit script が、正しく整形されていないGoコードがコミットされるのを防ぐpre-commitフックとなっています。Mercurialを使っている場合は、hgstyle plugin がgofmtのpre-commitフックを提供しています。

機械的なソース変換

機械整形されたコードの最大の美点の一つは、diffの中に整形とは無関係なノイズを発生させることなく機械的に変換できることです。機械的な変換は、大規模なコードベースを扱うときに非常に有用です。手作業で広範囲にわたる変更を行うよりも網羅的であり、かつエラーが起きにくいからです。実際、(私たちがGoogleで行っているように)大規模に作業する場合、こうした種類の変更を手作業で行うのは現実的ではないことがよくあります。

Goのコードを機械的に操作する最も簡単な方法は、gofmtの -r フラグを使うことです。このフラグは次のような形の書き換えルールを指定します。

pattern -> replacement

ここで patternreplacement はどちらも正しいGoの式です。pattern の中では、1文字の小文字の識別子が任意の部分式にマッチするワイルドカードとして働き、それらの式は replacement 内の同じ識別子の位置に代入されます。

例えば、Goのコアに対するこの最近の変更では、bytes.Compare のいくつかの使用箇所を、より効率的な bytes.Equal を使うように書き換えました。このコントリビューターは、たった2回のgofmtの呼び出しでこの変更を行いました。

gofmt -r 'bytes.Compare(a, b) == 0 -> bytes.Equal(a, b)'
gofmt -r 'bytes.Compare(a, b) != 0 -> !bytes.Equal(a, b)'

Gofmtは gofix も可能にしています。これは任意の複雑さを持つソース変換を行えるツールです。Gofixは、私たちが言語やライブラリに対して互換性を壊す変更を定期的に行っていた初期の頃、非常に貴重なツールでした。例えば、Go 1より前には組み込みの error インターフェースは存在せず、慣習として os.Error 型が使われていました。errorを導入したとき、私たちは os.Error とその関連するヘルパー関数へのすべての参照を、error と新しい errorsパッケージ を使うように書き換えるgofixモジュールを提供しました。これは手作業で試みるにはとても骨の折れる作業だったでしょうが、コードが標準的なフォーマットになっていたおかげで、現存するほぼすべてのGoコードに影響を与えたこの変更を、準備し、実行し、レビューするのが比較的容易になりました。

gofixについての詳細は、この記事を参照してください。

By Andrew Gerrand