Files
OpenFlare/.agents/skills/go-performance/references/STRING-OPTIMIZATION.md
T
2026-08-04 11:40:32 +08:00

135 lines
2.9 KiB
Markdown

# 字符串优化模式
## strconv vs fmt
在基本类型和字符串之间转换时,`strconv` 比 `fmt` 更快,因为 `fmt` 使用反射并处理任意类型。
**不好:**
```go
for i := 0; i < b.N; i++ {
s := fmt.Sprint(rand.Int())
}
```
**好:**
```go
for i := 0; i < b.N; i++ {
s := strconv.Itoa(rand.Int())
}
```
**基准测试比较:**
| 方式 | 速度 | 分配次数 |
|------|------|---------|
| `fmt.Sprint` | 143 ns/op | 2 allocs/op |
| `strconv.Itoa` | 64.2 ns/op | 1 allocs/op |
常用转换:
| 任务 | `fmt` | `strconv` |
|------|-------|-----------|
| Int → string | `fmt.Sprint(n)` | `strconv.Itoa(n)` |
| Int64 → string | `fmt.Sprint(n)` | `strconv.FormatInt(n, 10)` |
| Float → string | `fmt.Sprint(f)` | `strconv.FormatFloat(f, 'f', -1, 64)` |
| String → int | — | `strconv.Atoi(s)` |
| Bool → string | `fmt.Sprint(b)` | `strconv.FormatBool(b)` |
---
## 重复的字符串到字节转换
不要重复从固定字符串创建字节切片。应该只转换一次并保存结果。
**不好:**
```go
for i := 0; i < b.N; i++ {
w.Write([]byte("Hello world"))
}
```
**好:**
```go
data := []byte("Hello world")
for i := 0; i < b.N; i++ {
w.Write(data)
}
```
**基准测试比较:**
| 方式 | 速度 |
|------|------|
| 重复转换 | 22.2 ns/op |
| 单次转换 | 3.25 ns/op |
好的版本**快约 7 倍**,因为它避免了每次迭代都分配新的字节切片。
---
## 字符串拼接
根据复杂度选择正确的字符串构建策略。
### 简单场景使用 `+`
```go
key := "projectid: " + p
```
`+` 运算符对于少量、固定数量的字符串是高效的。编译器通常可以优化相邻的字符串字面量。
### 格式化使用 `fmt.Sprintf`
```go
// 好:清晰的格式化
str := fmt.Sprintf("%s [%s:%d]-> %s", src, qos, mtu, dst)
// 不好:使用 + 手动转换
str := src.String() + " [" + qos.String() + ":" + strconv.Itoa(mtu) + "]-> " + dst.String()
```
当写入 `io.Writer` 时,直接使用 `fmt.Fprintf` 而不是先用 `fmt.Sprintf` 构建临时字符串。
### 逐段构建使用 `strings.Builder`
`strings.Builder` 花费摊销线性时间,而重复使用 `+` 或
`fmt.Sprintf` 在构建大字符串时花费二次时间:
```go
b := new(strings.Builder)
for i, d := range digitsOfPi {
fmt.Fprintf(b, "the %d digit of pi is: %d\n", i, d)
}
str := b.String()
```
### 常量多行字符串使用反引号
```go
// 好:原始字符串字面量
usage := `Usage:
custom_tool [args]`
// 不好:使用转义序列拼接
usage := "" +
"Usage:\n" +
"\n" +
"custom_tool [args]"
```
### 策略总结
| 方法 | 最佳用途 | 性能 |
|------|---------|------|
| `+` | 少量字符串,简单拼接 | 小 n 时 O(n) |
| `fmt.Sprintf` | 格式化输出 | 较慢,但更清晰 |
| `strings.Builder` | 循环/逐段构建 | 摊销 O(n) |
| `strings.Join` | 连接 slice | O(n) |
| 反引号字面量 | 常量多行文本 | 零开销 |