Go中字符串+拼接在循环里性能差,因每次分配新内存并复制全部内容,时间复杂度近O(n²);应改用strings.Builder预分配并复用底层数组,或批量时直接用strings.Join。
+ 拼接在循环里会严重拖慢性能Go 中字符串是不可变的,每次用 + 拼接都会分配新内存并复制全部内容。在循环中反复执行,时间复杂度接近 O(n²),尤其当拼接 1000+ 次、单次字符串超百字节时,GC 压力和内存分配开销会明显上升。
go test -bench 显示耗时随拼接次数非线性增长,pprof 报告大量 runtime.mallocgc 调用a + b 都触发 runtime.concatstrings,内部调用 mallocgc 分配新底层数组strings.Builder 替代 + 和 fmt.Sprintf
strings.Builder 是 Go 1.10+ 官方推荐的零拷贝拼接方案,底层复用 []byte 切片,仅在容量不足时扩容,避免中间字符串分配。
builder.Grow(n) 预估总长(如已知最终约 2KB,就传 2048),否则默认初始容量 0,首次 Write 就要扩容builder.String() 结果再做 + 拼接——这会立刻触发一次无意义的字符串复制fmt.Fprintf(&builder, ...) 处理简单字符串,它比 builder.WriteString() 多一层格式解析开销var builder strings.Builder
builder.Grow(1024) // 预分配
for _, s := range parts {
builder.WriteString(s)
}
result := builder.String() // 仅调用一次,且放在最后
bytes.Buffer 而不是 strings.Builder
bytes.Buffer 更通用,支持读写双向操作和更多 I/O 接口,但多一层抽象,且 String() 方法每次调用都做 copy(即使底层未变);strings.Builder 专为拼接优化,String() 是纯指针转换,零开销。
bytes.Buffer:需要后续调用 buffer.Bytes() 写入文件、网络,或需 buffer.Reset() 复用缓冲区,或需兼容 Go 1.9 及更早版本strings.Builder:纯拼接、只读结果、Go 1.10+、追求极致性能strings.Builder 的 Reset() 不清空底层切片,只是重置长度,复用成本更低strings.Join,别自己写循环当目标是把一个切片里的字符串

["a","b","c"] → "a,b,c"),strings.Join 内部已做最优预分配,比手写 Builder 循环快 10%~20%,且代码更简洁、不易出错。
for i, s := range ss { if i > 0 { b.WriteString(",") }; b.WriteString(s) }
result := strings.Join(ss, ","),前提是 ss 是 []string 类型sep := getSep()),仍可直接用,Join 对分隔符长度无特殊要求真正影响性能的从来不是单次拼接,而是拼接模式是否匹配数据特征——预分配、避免重复转换、选对工具类型,这三件事漏掉任何一项,都可能让优化效果打五折。