0x1 简明方法

  当程序的效率不是你所在意的问题的时候,fmt.Sprintf 方法是非常好用的:

1
var s = fmt.Sprintf("Hello, %s!", "kofj") // Hello, kofj!

0x2 Go 1.10 以下版本

  当我们构建高性能程序的时候,字符串连接的性能问题就是一个绕不开的问题了。字符串在 Golang 中是只读类型,这意味着你对字符串的操作会伴随内存冗余复制,这会导致效率低下;为了避免内存冗余复制,我们通常把字符串转化为 []byte 来操作(很多标准库的方法内部就是这么操作的),最后在必须的时候再转化回 string 类型。在 Go 1.10 之前,想要高效的构建字符串,我们可以新建一个 bytes.Buffer 缓冲器,然后使用 fmt.Fprintf 写入这个缓冲器中,最后再转换成 string 类型。

1
2
3
4
var buf bytes.Buffer
fmt.Fprintf(&buf, "Hi, I'm %s.", "Frank Kung")
s := buf.String() // Copy into a new string
fmt.Println(s)

  这个方案性能很棒,但是却可能会产生过多的垃圾,导致额外的 GC 。为了更高的性能,我们可以尝试 strconv 包中的 Append 系列函数。

0x3 使用 strings.Builder

  在本月最新发布的 Go 1.10 版本运行时中,新增了实现了 Writer 接口的 strings.Builder 类型用于高效的构建、连接字符串。

  • 它提供了一些bytes.Buffer方法的子集,可以安全地避免内存冗余复制。
  • Grow 方法可用于在已知字符串的最大大小时预先分配内存。
1
2
3
4
5
6
7
8
var b strings.Builder
b.Grow(32)
for i, p := range []int{2, 3, 5, 7, 11, 13} {
	fmt.Fprintf(&b, "%d:%d, ", i+1, p)
}
s := b.String()   // no copying
s = s[:b.Len()-2] // no copying (removes trailing ", ")
fmt.Println(s)

本文编译改写自《Build and concatenate strings efficiently》,内容非翻译。