go基础库之将字符串与writer连接

除了内置的+运算符之外,还有更多的方法可以连接字符串。本篇将用bytes包和内置copy函数,作为连接字符串的更有效的方法。

将字符串与writer连接

Golang 版本

1.12.1

前言

除了内置的+运算符之外,还有更多的方法可以连接字符串。本篇将用bytes包和内置copy函数,作为连接字符串的更有效的方法。

实现

  1. 创建文件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
    
  2. 创建文件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