「eg tool」で検索してたどり着くのは、多くの場合Go公式ツール群 golang.org/x/tools に含まれる eg コマンドです。GUIアプリでも独立した製品でもなく、コード例(example)でリファクタリングを指定するコマンドラインツールで、名前は「e.g.(例えば)」に由来します。この記事では、その導入方法・テンプレート(before/after関数)の書き方・実行手順・使えない場面までを一次情報にもとづいて整理します。
まとめ:egは「変換前後のコード例」で一括置換するGoのリファクタリングツール
- 正体:
golang.org/x/tools/cmd/eg。Goのソースを型情報つきで解析し、パターンに一致する式をまとめて置換する。 - 導入:
go install golang.org/x/tools/cmd/eg@latestの1行。 - 指定方法:
before/afterという同じ型の関数2つを書いたテンプレートファイルを渡す。beforeが検索パターン、afterが置換後。 - 実行:
eg -t template.go <パッケージ>で結果を標準出力に確認し、問題なければ-wで上書き。 - 限界:置換できるのは「式→式」だけ。文の書き換え・型をまたぐ一般化はできず、追加されたimportは自動削除されない(
goimportsで後処理)。
egとは:型を理解して式を置換するexample-based refactoring
egは、正規表現ではなく実際のGoコードの例で「この式をこの式に置き換えたい」と宣言する方式のリファクタリングツールです。指定したパッケージ内のすべてのGoコードを解析し、パターンに一致する箇所を置換後の式に書き換えます。
特徴は、単なる文字列置換ではなく型情報を使って一致を判定する点です。同名のメソッドでもレシーバの型が違えば誤爆せず、意味的に同じ式だけを対象にできます。ソースコードを実行せずに構造と型を読む点は静的解析とは何か?ソースコードを実行せずに品質を確保する手法で扱う静的解析の一種で、egはその仕組みを「一括書き換え」に応用したものと捉えると理解しやすい。
インストールと基本コマンド
Goがインストール済みなら、次の1行で $GOPATH/bin(通常 $HOME/go/bin)に eg が入ります。
go install golang.org/x/tools/cmd/eg@latest
基本の呼び出し形は次のとおりです。<パッケージ> にはインポートパスや ./...(カレント配下すべて)を指定します。
eg -t template.go [-w] [-transitive] <パッケージ>
主なフラグは以下です。
| フラグ | 意味 |
|---|---|
-t template.go |
リファクタリングを定義するテンプレートファイル(必須) |
-w |
結果を標準出力ではなく元ファイルへ直接書き戻す |
-transitive |
指定パッケージだけでなく依存先パッケージも対象にする |
-tags tag,... |
適用するビルドタグ(カンマ区切り) |
-beforeedit cmd |
各ファイルを編集する前に実行するコマンド。{} がファイル名に置換される(例:チェックアウトやchmod) |
-v |
マッチングの詳細診断を表示する |
-help |
テンプレートの説明を含む詳細ヘルプを表示する |
テンプレート(before/after関数)の書き方
変換内容は、同じ型シグネチャを持つ before と after の2関数を書いたGoファイルで指定します。各関数の本体は「1つの式(return文または式文)」だけにします。beforeの式がパターン、afterの式が置換後です。
package P
import (
"errors"
"fmt"
)
func before(s string) error { return fmt.Errorf("%s", s) }
func after(s string) error { return errors.New(s) }
関数の引数はワイルドカードとして働き、その型に代入可能な任意の式に一致します。同じ引数がパターン内に複数回現れる場合は、入力側でも同一の式でなければ一致しません。上のテンプレートを次のように適用すると、
eg -t template.go -w ./...
コード中の fmt.Errorf("%s", "error: "+msg) が errors.New("error: "+msg) に置き換わります。"error: "+msg という具体的な式がワイルドカード s に収まっている点が、型を見たうえでの一致です。
実行手順:まず標準出力で確認し、-wで確定する
egは破壊的な一括置換なので、いきなり -w を付けないのが安全です。手順は次のようにします。
- 差分を確認:
-wなしでeg -t template.go ./...を実行すると、書き換え後のコードが標準出力に出る。意図しない箇所が変わっていないか目視する。 - 書き戻し:問題なければ
-wを付けて再実行し、ファイルへ反映する。 - 依存先も直す:ライブラリ側のAPI変更に追随するなど、依存パッケージまで一括で直したいときだけ
-transitiveを足す。 - 編集前フック:バージョン管理で読み取り専用のファイルを扱う場合などは、
-beforeeditにチェックアウトコマンドを渡す。
非推奨になったAPIの呼び出しを新APIへ機械的に寄せる、社内共通ライブラリの関数名変更に全リポジトリで追随する、といった「同じ形の式を何百箇所も直す」場面で威力を発揮します。手作業の置換と違い型で判定するため、たまたま文字列が一致しただけの別物を巻き込みません。リファクタリングをどの時点で入れるべきかの判断はリファクタリングを行うべきタイミングとその判断基準を参照してください。
egが苦手な場面:式単位という制約を先に知る
egは万能ではありません。設計上できないことを先に把握しておくと、無理な使い方で時間を溶かさずに済みます。公式ヘルプが挙げる主な制約は次のとおりです。
- 置換できるのは「式」だけ:文(if文・代入文・複数ステートメント)の書き換えには使えない。
- 型をまたぐ一般化ができない:intやint64など「すべての整数型」といったまとめ方や、置換前後で型が変わる変換は表現できない。
- 関数リテラルはパターンに書いても一致しない。
- 構造体リテラルの表記ゆれ:
T{x}とT{K: x}を1つのテンプレートで両方一致させることはできない。 - ドットインポート禁止:テンプレート内でドットインポートは使えない。ドットインポートや別名インポートを含むコードでは、置換結果の識別子が正しくならないことがある。
- importは足すが消さない:置換で新たに必要になったimportは自動追加されるが、不要になったimportは残る。仕上げに
goimportsを通す。
また公式ドキュメント自身が「変換が型エラーを生まないと保証するのは一般には非常に複雑」と明記しています。置換後は必ずコンパイルとテストで検証する前提のツールだと考え、無検証で -w を回さないことが実務上の鉄則です。
他のリファクタリング手段との使い分け
Goには目的別に別の手段があり、egが向くのは「同じ形の式を型安全に一括置換する」ケースに絞られます。
| やりたいこと | 向くツール |
|---|---|
| 同じ形の式を型を見て一括置換 | eg |
| 構文ベースの単純な書き換え | gofmt -r |
| 識別子(変数・関数・型名)の改名 | gopls のrename/gorename |
| 抽出・移動などIDE上の対話的な操作 | IDEのリファクタリング機能 |
gofmt -r は構文パターンで置換するため手軽ですが型を見ません。egは型情報を使う分、意味的に同じ式だけを狙えます。一方、変数名や関数名そのものを変えたいなら改名専用の gopls/gorename が適切で、egの守備範囲ではありません。IDEでの抽出・移動を含む対話的な操作についてはIntelliJ IDEAとEclipseの違いを徹底比較|補完・Spring・料金と選び方【2026】も参考になります。コード品質改善を自動化ツール全体でどう組むかはコード品質管理における自動化ツールの活用方法で整理しています。
よくある質問
egの読み方と名前の由来は?
「e.g.(exempli gratia=例えば)」に由来する名前で、コード例でリファクタリングを指定する方式を表しています。コマンド名としては eg の2文字です。
「eg.go」とは何ですか?
eg.go はegコマンド本体のソースファイル名です(cmd/eg/eg.go、および実装本体の refactor/eg/eg.go)。ツールの中身を確認したいときに読むファイルで、別製品ではありません。
「eg software」「eg tools」という別のソフトですか?
検索では紛れますが、「eg software」「eg tools」(複数形)と表記されるものも、指しているのはこのGoのコマンドラインツール eg です。独立したパッケージソフトやGUIアプリケーションではありません。
gofmt -rとの違いは?
gofmt -r は構文パターンによる置換で型を考慮しません。egは型情報を使って一致を判定するため、名前が同じでも型の異なる式を巻き込まずに置換できます。
置換後にimportが壊れたように見えるのはなぜ?
egは必要なimportを追加しますが、不要になったimportの削除は行いません。実行後に goimports を通してimportを整理してください。