There's more...

Just for comparison, there is a benchmark code, which compares the performance of the built-in + operator, bytes.Buffer, and built-in copy:

  1. Create a bench folder and file bench_test.go in it with the following content:
        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()
}
  1. See the results of the benchmark run: