前言

在日常开发中,写过的最多代码之一就是字符串拼接,比如日志输入拼接,响应参数拼接等等,那么在 Golang 都有哪些方法来拼接字符串呢?以及他们的效率如何,这次我们就来测试一下。

方式

“+” 或 ”+=”

// 字符串相加
func stringPlus(s string, count int) (res string) {
    for i := 0; i < count; i++ {res += s}
    return
}

fmt 内置库

//fmt.Sprintf
func stringFmtSprintf(s string, count int) (res string) {
    for i := 0; i < count; i++ {res = fmt.Sprintf("%s%s", res, s)
    }
    return
}

bytes.Buffer

//bytes.Buffer
func stringBytesBuffer(s string, count int) (res string) {buf := &bytes.Buffer{}
    for i := 0; i < count; i++ {buf.WriteString(s)
    }
    res = buf.String()
    return
}

strings.Builder

//strings.Builder
func stringStringsBuilder(s string, count int) (res string) {build := &strings.Builder{}
    for i := 0; i < count; i++ {build.WriteString(s)
    }
    res = build.String()
    return
}

[]byte


//byte 切片
func stringByteSlice(s string, count int) (res string) {b := make([]byte, len(s))
    for i := 0; i < count; i++ {b = append(b, s...)
    }
    res = string(b)
    return
}

性能

上面举例了 golang 中常见的五种字符串拼接方式,那么他们的拼接性能如何呢?我们来用基准测试测试一下:

package main
 
import "testing"
 
const (
    testString = "a"
    testCount = 1000
)
 
func BenchmarkStringPlus(b *testing.B) {
    for i := 0; i < b.N; i++ {stringPlus(testString, testCount)
    }
}
 
func BenchmarkStringFmtSprintf(b *testing.B) {
    for i := 0; i < b.N; i++ {stringFmtSprintf(testString, testCount)
    }
}
 
func BenchmarkStringBytesBuffer(b *testing.B) {
    for i := 0; i < b.N; i++ {stringBytesBuffer(testString, testCount)
    }
}
 
func BenchmarkStringStringsBuilder(b *testing.B) {
    for i := 0; i < b.N; i++ {stringStringsBuilder(testString, testCount)
    }
}
 
func BenchmarkStringByteSlice(b *testing.B) {
    for i := 0; i < b.N; i++ {stringByteSlice(testString, testCount)
    }
}

结果为:

goos: windows
goarch: amd64
pkg: go-juejin/strappend
cpu: Intel(R) Core(TM) i5-9400F CPU @ 2.90GHz
BenchmarkStringPlus
BenchmarkStringPlus-6                   9313        129762 ns/op
BenchmarkStringFmtSprintf
BenchmarkStringFmtSprintf-6             4152        260648 ns/op
BenchmarkStringBytesBuffer
BenchmarkStringBytesBuffer-6          181897          6579 ns/op
BenchmarkStringStringsBuilder
BenchmarkStringStringsBuilder-6       280454          4355 ns/op
BenchmarkStringByteSlice
BenchmarkStringByteSlice-6            925546          1212 ns/op
PASS
[]bytefmt.Sprintf[]byte