Go字符串拼接需按场景选方法:2~3个静态字符串用+;字符串切片用strings.Join;循环拼接用strings.Builder;混合类型格式化用fmt.Sprintf但避免高频使用。
Go 里拼接字符串不能“随便加”,选错方法可能让性能掉一个数量级,尤其在循环里用 + 拼接,实际是 O(n²) 的隐式拷贝。
+ 最安全只适用于 2~3 个已知字符串的静态拼接,比如日志前缀、固定提示语。编译器能做常量折叠,几乎零开销。
msg := "User " + name + " logged in"
s += item 在 for 循环里反复调用——每次都会新建字符串、复制全部字节
+ 不自动转类型,"ID: " + 123 会编译失败,必须显式用 strconv.Itoa 或 fmt.Sprint
strings.Join
当你手头是一组字符串(比如命令行参数、配置项、HTTP 头列表),strings.Join 是最简洁高效的选择,它预分配内存,一次拷贝完成。
parts := []string{"a", "b", "c"}; result := strings.Join(parts, ", ")
[]int{1,2,3} 得先遍历转成 []string,再 Join
strings.Join([]string{"hello", "world"}, "") 不如直接写 "hello" + "world"
strings.Builder
这是 Go 1.10+ 官方推荐的高性能方案,底层用可增长的 []byte 缓存,避免重复分配,比

bytes.Buffer 更轻量(无锁、专为字符串设计)。
var b strings.Builder
b.Grow(1024) // 预估长度,减少扩容
for _, v := range data {
b.WriteString(v)
b.WriteString(";")
}
result := b.String()b.String() 后继续 WriteString 会 panic;重用 Builder 请调 b.Reset(),别重新声明变量Builder 零值有效,但复制后状态不共享fmt.Sprintf,但别滥用当你要把 int、float64、结构体等直接塞进字符串时,fmt.Sprintf 语义清晰,但有反射和格式解析开销,不适合高频拼接。
log.Printf("failed to parse %s: %v", filename, err)
strconv.Itoa + Builder.WriteString 比 fmt.Sprintf("%d", i) 快 3~5 倍fmt.Sprintln 自动加空格和换行,适合日志,但别误用在协议拼接里真正容易被忽略的是:字符串不可变这个事实本身。不是“怎么拼更快”,而是“每次拼都在造新对象”。所以关键不是记住五种方法,而是看清楚你手里的数据形态——是固定几个值?是一堆切片?还是边读边拼?选对入口,后面就自然了。