技術
約2分で読めます
Go 1.26のgo fixが大幅進化 - コードの自動モダナイゼーションツールとして生まれ変わった
Go 1.26でgo fixサブコマンドが完全に書き直された。単なるコード修正ツールから、Goコードベースを最新のイディオムに自動変換する「モダナイザー」へと進化している。Go公式ブログでの詳細な解説記事が公開された。
基本的な使い方
# カレントディレクトリ配下のすべてのパッケージを修正
go fix ./...
# 変更内容をプレビュー(実際には変更しない)
go fix -diff ./...
# 利用可能なフィクサー一覧
go tool fix help
主要なフィクサー
interface{}からanyへの自動変換
Go 1.18で導入されたanyエイリアスを使い、古いinterface{}を一括置換する。
// Before
func foo(x interface{}) {}
// After
func foo(x any) {}
min/max組み込み関数の活用
手動のif文によるクランプ処理を、Go 1.21の組み込みmin/max関数に変換する。
// Before
x := f()
if x < 0 { x = 0 }
if x > 100 { x = 100 }
// After
x := min(max(f(), 0), 100)
rangeint - Go 1.22の範囲ループ
カウンター変数を使わないループを、Go 1.22のrange整数構文に変換する。
// Before
for i := 0; i < n; i++ { f() }
// After
for range n { f() }
new(expr) - Go 1.26の新構文
これがGo 1.26の目玉だ。従来new()は型しか取れなかったが、値を直接渡せるようになった。
// Before - よくあるヘルパー関数パターン
func newInt(x int) *int { return &x }
data, _ := json.Marshal(&Request{Attempts: newInt(10)})
// After - ヘルパー関数が不要に
data, _ := json.Marshal(&Request{Attempts: new(10)})
go fix -newexpr ./...を実行すると、newIntのようなヘルパー関数の検出、return new(x)への置換、呼び出し箇所の直接new(expr)への書き換えが自動で行われる。proto.Int64やproto.Stringのようなヘルパーも不要になる。
その他のフィクサー
- stringscut:
strings.IndexByteパターンをstrings.Cutに変換 - forvar: Go 1.22以降不要になったループ変数シャドーイングを削除
- fmtappendf:
[]byte(fmt.Sprintf(...))をfmt.Appendfに変換 - stringsbuilder: ループ内の文字列連結を
strings.Builderに置換
相乗効果
複数のフィクサーを連続適用すると、相乗効果で更に最適化が進む場合がある。通常2回の実行で固定点に達するとのことだ。
パフォーマンス改善
内部的にも大きな改善が入っている。typeindexによる関数呼び出しのプレコンピュート索引化では、1000倍の高速化を達成した例もあるという。
new(expr)への自動変換でnewInt系ヘルパーを一掃できるのが地味にでかい。Go 1.26に上げたらまずgo fix ./...を叩く、でよさそう。