func BenchmarkBuffer(b *testing.B) {
text := "test"
b.ResetTimer()
buffer := bytes.Buffer{}
for i := 0; i < b.N; i++ {
buffer.WriteString(text)
}
buffer.String()
}
func BenchmarkBuilder(b *testing.B) {
text := "test"
b.ResetTimer()
builder := strings.Builder{}
for i := 0; i < b.N; i++ {
builder.WriteString(text)
}
builder.String()
}
func BenchmarkString(b *testing.B) {
text := "test"
b.ResetTimer()
for i := 0; i < b.N; i++ {
text += "test"
}
}
结果
goos: windows
goarch: amd64
pkg: test/one
BenchmarkBuffer
BenchmarkBuffer-12 181560793 8.03 ns/op
BenchmarkBuilder
BenchmarkBuilder-12 360210758 3.86 ns/op
BenchmarkString
BenchmarkString-12 353895 96676 ns/op
func BenchmarkBuffer(b *testing.B) {
text := ""
b.ResetTimer()
for i := 0; i < b.N; i++ {
buffer := bytes.Buffer{}
buffer.WriteString(text)
buffer.WriteString(text)
buffer.String()
}
}
func BenchmarkBuilder(b *testing.B) {
text := ""
b.ResetTimer()
for i := 0; i < b.N; i++ {
builder := strings.Builder{}
builder.WriteString(text)
builder.WriteString(text)
builder.String()
}
}
func BenchmarkString(b *testing.B) {
text := ""
b.ResetTimer()
for i := 0; i < b.N; i++ {
text = ""
text += ""
}
}
结果
goos: windows
goarch: amd64
pkg: test/one
BenchmarkBuffer
BenchmarkBuffer-12 136879110 8.73 ns/op
BenchmarkBuilder
BenchmarkBuilder-12 499198370 2.44 ns/op
BenchmarkString
BenchmarkString-12 276599348 4.29 ns/op
第二种空字符串的可能在应用上基本不会用到,通常情况下我们用builder和buffer会比+快很多。
func (b *Builder) WriteString(s string) (int, error) {
b.copyCheck()
b.buf = append(b.buf, s...)
return len(s), nil
}
builder的字符串相加就是直接用的append
func (b *Buffer) WriteString(s string) (n int, err error) {
b.lastRead = opInvalid
m, ok := b.tryGrowByReslice(len(s))
if !ok {
m = b.grow(len(s))
}
return copy(b.buf[m:], s), nil
}
buffer的字符串相加用的是copy,不同的是它会先去判断现有buf够不够长,不够的话会进行2倍的扩容
func concatstrings(buf *tmpBuf, a []string) string {
idx := 0
l := 0
count := 0
for i, x := range a {
n := len(x)
if n == 0 {
continue
}
if l+n < l {
throw("string concatenation too long")
}
l += n
count++
idx = i
}
if count == 0 {
return ""
}
// If there is just one string and either it is not on the stack
// or our result does not escape the calling frame (buf != nil),
// then we can return that string directly.
if count == 1 && (buf != nil || !stringDataOnStack(a[idx])) {
return a[idx]
}
s, b := rawstringtmp(buf, l)
for _, x := range a {
copy(b, x)
b = b[len(x):]
}
return s
}
而+号则是先把相加的字符串变成数组再设置总长度,最后才是拷贝