How to efficiently concatenate strings in Go?

2019-01-05 06:20发布

In Go, a string is a primitive type, which means it is read-only, and every manipulation of it will create a new string.

So if I want to concatenate strings many times without knowing the length of the resulting string, what's the best way to do it?

The naive way would be:

s := ""
for i := 0; i < 1000; i++ {
    s += getShortStringFromSomewhere()
}
return s

but that does not seem very efficient.

20条回答
贪生不怕死
2楼-- · 2019-01-05 07:16

My original suggestion was

s12 := fmt.Sprint(s1,s2)

But above answer using bytes.Buffer - WriteString() is the most efficient way.

My initial suggestion uses reflection and a type switch. See (p *pp) doPrint and (p *pp) printArg
There is no universal Stringer() interface for basic types, as I had naively thought.

At least though, Sprint() internally uses a bytes.Buffer. Thus

`s12 := fmt.Sprint(s1,s2,s3,s4,...,s1000)`

is acceptable in terms of memory allocations.

=> Sprint() concatenation can be used for quick debug output.
=> Otherwise use bytes.Buffer ... WriteString

查看更多
Animai°情兽
3楼-- · 2019-01-05 07:18

Note added in 2018

From Go 1.10 there is the strings.Builder type, which achieves this even more efficiently (for strings). The example given there is succinct and easy to copy/adapt.

Pre-201x answer

The best way is to use the bytes package. It has a Buffer type which implements io.Writer.

package main

import (
    "bytes"
    "fmt"
)

func main() {
    var buffer bytes.Buffer

    for i := 0; i < 1000; i++ {
        buffer.WriteString("a")
    }

    fmt.Println(buffer.String())
}

This does it in O(n) time.

查看更多
Summer. ? 凉城
4楼-- · 2019-01-05 07:19
package main

import (
"fmt"
)

func main() {
    var str1 = "string1"
    var str2 = "string2"
    result := make([]byte, 0)
    result = append(result, []byte(str1)...)
    result = append(result, []byte(str2)...)
    result = append(result, []byte(str1)...)
    result = append(result, []byte(str2)...)

    fmt.Println(string(result))
}
查看更多
三岁会撩人
5楼-- · 2019-01-05 07:23

I do it using the following :-

package main

import (
    "fmt"
    "strings"
)

func main (){
    concatenation:= strings.Join([]string{"a","b","c"},"") //where second parameter is a separator. 
    fmt.Println(concatenation) //abc
}
查看更多
Melony?
6楼-- · 2019-01-05 07:23

For those who come from the Java world where we have StringBuilder for efficient string concatenation, it seems like the latest go version has its equivalent and it's called Builder: https://github.com/golang/go/blob/master/src/strings/builder.go

查看更多
Anthone
7楼-- · 2019-01-05 07:25

Expanding on cd1's answer: You might use append() instead of copy(). append() makes ever bigger advance provisions, costing a little more memory, but saving time. I added two more benchmarks at the top of yours. Run locally with

go test -bench=. -benchtime=100ms

On my thinkpad T400s it yields:

BenchmarkAppendEmpty    50000000         5.0 ns/op
BenchmarkAppendPrealloc 50000000         3.5 ns/op
BenchmarkCopy           20000000        10.2 ns/op
查看更多
登录 后发表回答