除了内置的+运算符之外,还有更多的方法可以连接字符串。本篇将用bytes
包和内置copy
函数,作为连接字符串的更有效的方法。
将字符串与writer连接
Golang 版本
1.12.1
前言
除了内置的+运算符之外,还有更多的方法可以连接字符串。本篇将用bytes
包和内置copy
函数,作为连接字符串的更有效的方法。
实现
创建文件
concat_buffer.go
,代码如下:package main import ( "bytes" "fmt" ) func main() { strings := []string{"This ", "is ", "even ", "more ", "performant "} buffer := bytes.Buffer{} for _, val := range strings { buffer.WriteString(val) } fmt.Println(buffer.String()) }
$ go run concat_buffer.go This is even more performant
创建文件
concat_copy.go
,代码如下:package main import ( "fmt" ) func main() { strings := []string{"This ", "is ", "even ", "more ", "performant "} bs := make([]byte, 100) bl := 0 for _, val := range strings { bl += copy(bs[bl:], []byte(val)) } fmt.Println(string(bs[:])) }
$ go run concat_copy.go This is even more performant
原理
步骤1使用bytes
包的Buffer
作为字符串连接性能友好的解决方案。Buffer
结构体实现WriteString
方法,该方法可用于有效地将字符串连接到底层字节片中。
没有必要在所有情况下都使用这种改进,只要考虑一下程序将连接大量字符串的情况(例如,内存中的CSV导出和其他)。
步骤2中提供的内置copy
函数可用于完成string
的连接。这种方法需要对最终字符串长度做一些假设,或者可以动态地完成。但是,如果写入结果的缓冲区的容量小于已经写入的部分和要追加的字符串的总和,则必须扩展缓冲区(通常通过分配容量更大的新片)。
延伸
仅作比较,有一个基准代码,用于比较内置+运算符bytes.Buffer
和内置copy
方法的性能:
创建文件夹bench
,并创建文件bench_test.go
,代码如下:
package main
import (
"bytes"
"testing"
)
const testString = "test"
func BenchmarkConcat(b *testing.B) {
var str string
b.ResetTimer()
for n := 0; n < b.N; n++ {
str += testString
}
b.StopTimer()
}
func BenchmarkBuffer(b *testing.B) {
var buffer bytes.Buffer
b.ResetTimer()
for n := 0; n < b.N; n++ {
buffer.WriteString(testString)
}
b.StopTimer()
}
func BenchmarkCopy(b *testing.B) {
bs := make([]byte, b.N)
bl := 0
b.ResetTimer()
for n := 0; n < b.N; n++ {
bl += copy(bs[bl:], testString)
}
b.StopTimer()
}
$ go test -bench=.
goos: windows
goarch: amd64
pkg: Go-Standard-library/Concatenating-a-string-with-writer/bench
BenchmarkConcat-4 300000 95719 ns/op
BenchmarkBuffer-4 100000000 12.6 ns/op
BenchmarkCopy-4 300000000 4.36 ns/op
PASS
ok Go-Standard-library/Concatenating-a-string-with-writer/bench 32.345s