Go中循环内用+拼接字符串性能差,因字符串不可变导致O(n²)复制;应优先用strings.Builder(预估容量、复用)或strings.Join(批量合并),避免bytes.Buffer滥用。

为什么 + 拼接在循环里很慢
Go 中字符串是不可变的,每次用 + 拼接都会分配新内存并复制全部内容。在循环中反复拼接时,时间复杂度接近 O(n²)——比如拼接 1000 个长度为 10 的字符串,底层可能复制上万字节。
- 单次拼接小字符串(如两三个变量)用
+完全没问题,编译器会优化 - 循环内、或拼接数量不确定时,
+是性能黑洞 -
fmt.Sprintf同样有分配开销,不适合高频拼接
用 strings.Builder 替代拼接循环
strings.Builder 是 Go 1.10+ 推荐的标准方案,内部用切片缓存,WriteString 避免重复分配,比 + 快 5–10 倍以上。
var b strings.Builder
b.Grow(1024) // 预估容量,减少扩容次数
for _, s := range strs {
b.WriteString(s)
}
result := b.String()
-
Grow(n)不是必须的,但能避免多次底层数组扩容 - 不要对同一个
Builder多次调用String()后继续写入——它不保证后续写入安全(虽当前实现可工作,但属未定义行为) - 用完可调用
Reset()复用,避免频繁新建对象
批量拼接优先用 strings.Join
如果只是把一个切片里的字符串用分隔符连起来,strings.Join 是最简、最快的选择。它预先计算总长,一次分配,零冗余拷贝。
result := strings.Join(strs, ", ")
- 比手写循环 +
Builder更简洁、更不易出错 - 底层已做容量预估,无需手动
Grow - 若分隔符为空(
""),效果等同于无分隔合并,仍高效
注意 bytes.Buffer 和 strings.Builder 的适用边界
bytes.Buffer 能干的事更多(支持写入字节、格式化、读取等),但接口更重;strings.Builder 专为字符串拼接设计,更轻量、更安全(不能误写入非 UTF-8 数据)。
立即学习“go语言免费学习笔记(深入)”;
- 纯字符串拼接 → 无条件选
strings.Builder - 需要写入
[]byte、或混用WriteRune/Writef→ 才考虑bytes.Buffer - 别为了“看起来统一”而在字符串场景硬用
bytes.Buffer,它多一层类型转换开销
+ 的隐式复制成本。预估长度、复用 Builder、该用 Join 就别手写,这三件事做对,字符串拼接基本就不再拖后腿。











