perfsprint

Table of Contents

  1. 解決する問題
  2. 設定
  3. オプション
  4. サンプル
    1. 検出例
    2. 修正例
  5. 注意点
  6. 参考リンク

perfsprint は fmt.Sprintf をより高速な代替関数(strconv 等)に置き換え可能な箇所を検出するツールです。

解決する問題

fmt.Sprintf はリフレクションを使用するため、型が明確な場合は strconv パッケージの関数を使う方が大幅に高速です。ベンチマークでは最大 100 倍の速度差とメモリ割り当てゼロを実現できます。

1
2
3
4
5
6
// Before: fmt.Sprintf を使用(遅い)
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
// After: strconv 等を使用(高速)
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
# .golangci.yml 設定例
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
// perfsprint が警告するパターン

// 1. 整数フォーマット
func formatID(id int) string {
return fmt.Sprintf("%d", id) // fmt.Sprintf can be replaced with strconv.Itoa
}

// 2. 真偽値フォーマット
func formatBool(b bool) string {
return fmt.Sprintf("%t", b) // fmt.Sprintf can be replaced with strconv.FormatBool
}

// 3. 文字列の冗長なフォーマット
func formatName(name string) string {
return fmt.Sprintf("%s", name) // fmt.Sprintf can be replaced with just using the string
}

// 4. エラー生成の最適化
func newError(msg string) error {
return fmt.Errorf(msg) // fmt.Errorf can be replaced with errors.New
}

// 5. 16 進数フォーマット
func formatHash(hash []byte) string {
return fmt.Sprintf("%x", hash) // fmt.Sprintf can be replaced with hex.EncodeToString
}

// 6. 文字列結合
func fullName(first, last string) string {
return fmt.Sprintf("%s %s", first, last) // fmt.Sprintf can be replaced with string concatenation
}

修正例

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 オプションでインポート文も自動修正される
  • ホットパス(頻繁に実行されるコード)で特に効果が大きい。ログ出力やメトリクス生成のような高頻度処理に優先的に適用すると効果的

参考リンク