perfsprint は fmt.Sprintf をより高速な代替関数(strconv 等)に置き換え可能な箇所を検出するツールです。
解決する問題
fmt.Sprintf はリフレクションを使用するため、型が明確な場合は strconv パッケージの関数を使う方が大幅に高速です。ベンチマークでは最大 100 倍の速度差とメモリ割り当てゼロを実現できます。
1 2 3 4 5 6
| func FormatUser(id int, name string, active bool) string { idStr := fmt.Sprintf("%d", id) activeStr := fmt.Sprintf("%t", active) return fmt.Sprintf("%s", name) + ":" + idStr + ":" + activeStr }
|
1 2 3 4 5 6
| func FormatUser(id int, name string, active bool) string { idStr := strconv.Itoa(id) activeStr := strconv.FormatBool(active) return name + ":" + idStr + ":" + activeStr }
|
設定
公式ドキュメント
1 2 3 4 5 6 7 8 9 10 11 12 13
| version: "2"
linters: enable: - perfsprint settings: perfsprint: int-conversion: true err-error: false errorf: true sprintf1: true strconcat: false
|
オプション
| オプション |
型 |
デフォルト |
説明 |
int-conversion |
bool |
true |
整数フォーマットの最適化。int キャストが追加される場合がある |
err-error |
bool |
false |
fmt.Sprintf("%s", err) → err.Error() への変換。nil エラーでパニックになる動作変更あり |
errorf |
bool |
true |
fmt.Errorf("msg") → errors.New("msg") への変換 |
sprintf1 |
bool |
true |
fmt.Sprintf("msg") → "msg" への変換 |
strconcat |
bool |
true |
fmt.Sprintf("%s%s", a, b) → a + b への文字列結合変換 |
bool-format |
bool |
true |
fmt.Sprintf("%t", b) → strconv.FormatBool(b) への変換 |
hex-format |
bool |
true |
fmt.Sprintf("%x", b) → hex.EncodeToString(b) への変換 |
サンプル
検出例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
func formatID(id int) string { return fmt.Sprintf("%d", id) }
func formatBool(b bool) string { return fmt.Sprintf("%t", b) }
func formatName(name string) string { return fmt.Sprintf("%s", name) }
func newError(msg string) error { return fmt.Errorf(msg) }
func formatHash(hash []byte) string { return fmt.Sprintf("%x", hash) }
func fullName(first, last string) string { return fmt.Sprintf("%s %s", first, last) }
|
修正例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| func formatID(id int) string { return strconv.Itoa(id) }
func formatBool(b bool) string { return strconv.FormatBool(b) }
func formatName(name string) string { return name }
func newError(msg string) error { return errors.New(msg) }
func formatHash(hash []byte) string { return hex.EncodeToString(hash) }
func fullName(first, last string) string { return first + " " + last }
|
注意点
err-error: true にすると fmt.Sprintf("%s", err) → err.Error() に変換されるが、err が nil の場合パニックになる動作変更がある。デフォルトでは無効
strconcat: false にすると文字列結合への変換を無効化できる。可読性を重視する場合に有用
int-conversion: true では int64 型に対して strconv.FormatInt(int64(x), 10) のようなキャストが追加される場合がある
- 自動修正(
--fix)に対応しており、fix-imports オプションでインポート文も自動修正される
- ホットパス(頻繁に実行されるコード)で特に効果が大きい。ログ出力やメトリクス生成のような高頻度処理に優先的に適用すると効果的
参考リンク