strings.Builder 更快,因其基于可增长 byte 切片实现零拷贝拼接,避免 string 不可变性导致的重复分配与复制,并支持预分配容量、高效写入及单次字符串转换。

在 Go 中频繁拼接字符串时,直接用 + 或 fmt.Sprintf 容易触发大量内存分配和拷贝,影响性能。推荐使用 strings.Builder —— 它底层基于可增长的 byte 切片,零拷贝、无额外字符串转换,是标准库中专为高效字符串构建设计的类型。
为什么 strings.Builder 更快?
Go 的 string 是不可变的,每次 + 拼接都会创建新字符串并复制内容;fmt.Sprintf 还需格式解析和反射开销。而 strings.Builder:
- 内部维护一个
[]byte缓冲区,支持预分配容量(Grow) - 写入方法(如
WriteString、WriteRune)直接追加字节,不产生中间字符串 -
String()方法只在最后做一次底层字节到字符串的只读转换(无拷贝) - 不持有对原始字节的引用,避免意外内存泄漏
正确使用 strings.Builder 的关键步骤
避免常见误用,才能真正发挥性能优势:
-
预估长度,调用
Grow(n):比如要拼接 10 个平均长度 20 的字符串,可先b.Grow(200),减少底层数组扩容次数 -
优先用
WriteString而非.WriteString(fmt.Sprint(x)):对整数等基本类型,直接用b.WriteString(strconv.Itoa(x))或fmt.Fprint(&b, x) -
不要重复调用
String():它每次都会新建字符串;如需多次使用结果,赋值给变量复用 - Builder 不是 goroutine 安全的:并发写入需自行加锁或每个 goroutine 独立实例
对比示例:+ 拼接 vs Builder
构造日志行的典型场景:
立即学习“go语言免费学习笔记(深入)”;
// ❌ 低效:每次 + 都分配新字符串
s := "user:" + strconv.Itoa(id) + ", name:" + name + ", time:" + time.Now().Format(time.RFC3339)
// ✅ 高效:Builder 一次分配、顺序写入
var b strings.Builder
b.Grow(128) // 预估足够容量
b.WriteString("user:")
b.WriteString(strconv.Itoa(id))
b.WriteString(", name:")
b.WriteString(name)
b.WriteString(", time:")
b.WriteString(time.Now().Format(time.RFC3339))
s := b.String()
其他实用技巧
进一步提升可读性与健壮性:
- 用
fmt.Fprint/fmt.Fprintf写入 Builder:支持多类型参数,比手动转字符串更简洁(底层仍高效) - 拼接后可调用
b.Reset()复用 Builder 实例,适合循环中反复构建不同字符串 - 注意 Builder 的零值可用,无需显式初始化(
var b strings.Builder即可) - 若最终结果要写入
io.Writer(如 HTTP 响应),可直接传 Builder(它实现了io.Writer)










