在 Go 中,astring是一种原始类型,这意味着它是只读的,每次对其进行操作都会创建一个新字符串。
string
因此,如果我想在不知道结果字符串长度的情况下多次连接字符串,那么最好的方法是什么?
天真的方法是:
var s string for i := 0; i < 1000; i++ { s += getShortStringFromSomewhere() } return s
但这似乎不是很有效。
从 Go 1.10 开始,有一种strings.Builder类型
strings.Builder
使用bytes包。它有一个Buffer实现io.Writer.
bytes
Buffer
io.Writer
package main import ( "bytes" "fmt" ) func main() { var buffer bytes.Buffer for i := 0; i < 1000; i++ { buffer.WriteString("a") } fmt.Println(buffer.String()) }
这是在 O(n) 时间内完成的。
在 Go 1.10+ 中strings.Builder,这里有。
Builder 用于使用 Write 方法有效地构建字符串。它最大限度地减少了内存复制。零值即可使用。
与bytes.Buffer.
bytes.Buffer
package main import ( "strings" "fmt" ) func main() { // ZERO-VALUE: // // It's ready to use from the get-go. // You don't need to initialize it. var sb strings.Builder for i := 0; i < 1000; i++ { sb.WriteString("a") } fmt.Println(sb.String()) }
单击以在操场上查看此内容。
StringBuilder 的方法是在考虑现有接口的情况下实现的。这样您就可以在代码中轻松切换到新的 Builder 类型。
它只能增长或重置。
它有一个内置的 copyCheck 机制,可以防止意外复制它:
func (b *Builder) copyCheck() { ... }
在bytes.Buffer,一个可以访问这样的底层字节:(*Buffer).Bytes()。
(*Buffer).Bytes()
strings.Builder 防止这个问题。
例如:对于将字节传递给io.Reader等时的偷看行为。
io.Reader
bytes.Buffer.Reset() 倒带并重用底层缓冲区,而strings.Builder.Reset() 不会,它分离缓冲区。
bytes.Buffer.Reset()
strings.Builder.Reset()