golang中字符串拼接性能依次是strings.builder>bytes.Buffer≈strings.Join>+ || fmt.Sprinf
拼接字符串都要经历“字符串创建、销毁、内存分配、数据拷贝等操作” 上面这里的差距主要体现在内存分配上 strings.builder比bytes.buffer性能好,是因为,bytes.buffer在往内存缓存中写入字符串时做了rune类型转换string时,产生了一个临时变量分配了内存,而string.builder是直接使用unsafe包将变量的类型转成了string.
而strings.Join看源码可以看出,最终使用的是string.builder,但在此之前也用到了临时变量,
而+或者fmt.Sprinf在连接前每个子串都会使用到临时变量
func (b *Builder) String() string {
return *(*string)(unsafe.Pointer(&b.buf))
}
func (b *Buffer) String() string {
if b == nil {
// Special case, useful in debugging.
return "<nil>"
}
return string(b.buf[b.off:])
}
func Join(elems []string, sep string) string {
switch len(elems) {
case 0:
return ""
case 1:
return elems[0]
}
n := len(sep) * (len(elems) - 1)
for i := 0; i < len(elems); i++ {
n += len(elems[i])
}
var b Builder
b.Grow(n)
b.WriteString(elems[0])
for _, s := range elems[1:] {
b.WriteString(sep)
b.WriteString(s)
}
return b.String()
}