问题描述
新方法:
从 Go 1.10 开始,有一种strings.Builder
类型
旧方式:
使用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+ 中,这里有。
Builder 用于使用 Write 方法有效地构建字符串。它最大限度地减少了内存复制。零值即可使用。
例子
与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 类型。
- Grow(int) -> bytes.Buffer#Grow
- Len() int -> bytes.Buffer#Len
- Reset() -> bytes.Buffer#Reset
- String() 字符串-> fmt.Stringer
- Write([]byte) (int, error) -> io.Writer
- WriteByte(byte) 错误-> io.ByteWriter
- WriteRune(rune) (int, error) -> bufio.Writer#WriteRune - bytes.Buffer#WriteRune
- WriteString(string) (int, error) -> io.stringWriter
与 bytes.Buffer 的区别
-
它只能增长或重置。
-
它有一个内置的 copyCheck 机制,可以防止意外复制它:
func (b *Builder) copyCheck() { ... }
-
在
bytes.Buffer
,一个可以访问这样的底层字节:(*Buffer).Bytes()
。 -
strings.Builder
防止这个问题。 - 有时,这不是问题,而是需要。
-
例如:对于将字节传递给
io.Reader
等时的偷看行为。 -
bytes.Buffer.Reset()
倒带并重用底层缓冲区,而strings.Builder.Reset()
不会,它分离缓冲区。
笔记
- 不要复制 StringBuilder 值,因为它会缓存基础数据。
- 如果要共享 StringBuilder 值,请使用指向它的指针。
解决方法
在 Go 中,astring
是一种原始类型,这意味着它是只读的,每次对其进行操作都会创建一个新字符串。
因此,如果我想在不知道结果字符串长度的情况下多次连接字符串,那么最好的方法是什么?
天真的方法是:
var s string
for i := 0; i < 1000; i++ {
s += getShortStringFromSomewhere()
}
return s
但这似乎不是很有效。