Golang高性能编程笔记--字符串拼接
Golang中引入五种字符串拼接方法,分别如下:
1.+拼接法
2.fmt.Sprintf()
3.strings.Builder
4.bytes.Buffer
5.[]byte
代码示例,这里将根据《Go语言高性能编程》中的一节,来看一下这五种具体的方法:
package main
import (
"bytes"
"fmt"
"math/rand"
"strings"
"time"
)
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
func GenerateRandomStr(n string) string {
var l = len(n)
b := make([]byte, l)
for i := range b {
rand.Seed(time.Now().UnixNano())
b[i] = letterBytes[rand.Intn(len(letterBytes))]
}
return string(b)
}
func PlusConcat(n int, str string) string {
s := ""
for i := 0; i < n; i++ {
s += str
}
return s
}
func sprintfConcat(n int, str string) string {
s := ""
for i := 0; i < n; i++ {
s = fmt.Sprintf("%s%s", s, str)
}
return s
}
func builderConcat(n int, str string) string {
var builder strings.Builder
for i := 0; i < n; i++ {
builder.WriteString(str)
}
return builder.String()
}
func bufferConcat(n int, s string) string {
buf := new(bytes.Buffer)
for i := 0; i < n; i++ {
buf.WriteString(s)
}
return buf.String()
}
func byteConcat(n int, str string) string {
buf := make([]byte, 0)
for i := 0; i < n; i++ {
buf = append(buf, str...)
}
return string(buf)
}
func main() {
var str = GenerateRandomStr("abcdefg")
fmt.Println(str)
fmt.Println("+拼接", PlusConcat(3, str))
fmt.Println("fmt.Sprintf:", sprintfConcat(3, str))
fmt.Println("strings.Builder:", builderConcat(3, str))
fmt.Println("bytes.Buffer:", bufferConcat(3, str))
fmt.Println("[]byte:", byteConcat(3, str))
}
官方给的建议是第三种:strings.Builder
golang对于第三种strngs.Builder还提供了预分配内存的模式:
func builderConcat(n int, str string) string {
var builder strings.Builder
builder.Grow(n * len(str))
for i := 0; i < n; i++ {
builder.WriteString(str)
}
return builder.String()
}
性能比较
首先看一下strings.Builder与+的差距大的原因:
字符串在 Go 语言中是不可变类型,占用内存大小是固定的,当使用 +
拼接 2 个字符串时,生成一个新的字符串,那么就需要开辟一段新的空间,新空间的大小是原来两个字符串的大小之和。拼接第三个字符串时,再开辟一段新空间,新空间大小是三个字符串大小之和,以此类推。
strings.Builder
,bytes.Buffer
,包括切片 []byte
的内存是以倍数申请的。例如,初始大小为 0,当第一次写入大小为 10 byte 的字符串时,则会申请大小为 16 byte 的内存(恰好大于 10 byte 的 2 的指数),第二次写入 10 byte 时,内存不够,则申请 32 byte 的内存,第三次写入内存足够,则不申请新的,以此类推。
strings.Builder与bytes.Buffer,[]byte的分析
strings.Builder
和 bytes.Buffer
底层都是 []byte
数组,但 strings.Builder
性能比 bytes.Buffer
略快约 10% 。一个比较重要的区别在于,bytes.Buffer
转化为字符串时重新申请了一块空间,存放生成的字符串变量,而 strings.Builder
直接将底层的 []byte
转换成了字符串类型返回了回来。