mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-28 05:46:36 +08:00
2.9 KiB
2.9 KiB
字符串优化模式
strconv vs fmt
在基本类型和字符串之间转换时,strconv 比 fmt 更快,因为 fmt 使用反射并处理任意类型。
不好:
for i := 0; i < b.N; i++ {
s := fmt.Sprint(rand.Int())
}
好:
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) |
重复的字符串到字节转换
不要重复从固定字符串创建字节切片。应该只转换一次并保存结果。
不好:
for i := 0; i < b.N; i++ {
w.Write([]byte("Hello world"))
}
好:
data := []byte("Hello world")
for i := 0; i < b.N; i++ {
w.Write(data)
}
基准测试比较:
| 方式 | 速度 |
|---|---|
| 重复转换 | 22.2 ns/op |
| 单次转换 | 3.25 ns/op |
好的版本快约 7 倍,因为它避免了每次迭代都分配新的字节切片。
字符串拼接
根据复杂度选择正确的字符串构建策略。
简单场景使用 +
key := "projectid: " + p
+ 运算符对于少量、固定数量的字符串是高效的。编译器通常可以优化相邻的字符串字面量。
格式化使用 fmt.Sprintf
// 好:清晰的格式化
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 在构建大字符串时花费二次时间:
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()
常量多行字符串使用反引号
// 好:原始字符串字面量
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) |
| 反引号字面量 | 常量多行文本 | 零开销 |