在Go中,字符串是一种基本类型,这意味着它是只读的,对它的每次操作都会创建一个新字符串。

如果我想多次连接字符串而不知道结果字符串的长度,最好的方法是什么?

最天真的做法是:

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

但这似乎不是很有效。


当前回答

新方法:

从Go 1.10开始,有一个字符串。建造者类型,请看看这个答案的更多细节。

老方法:

使用bytes包。它有一个实现io.Writer的Buffer类型。

package main

import (
    "bytes"
    "fmt"
)

func main() {
    var buffer bytes.Buffer

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

    fmt.Println(buffer.String())
}

它在O(n)时间内完成。

其他回答

我最初的建议是

s12 := fmt.Sprint(s1,s2)

但以上答案使用字节。Buffer - WriteString()是最有效的方法。

我最初的建议是使用反射和类型开关。参见(p *pp) doPrint和(p *pp) printArg 我曾经天真地认为,基本类型没有通用的Stringer()接口。

至少Sprint()内部使用bytes.Buffer。因此

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

在内存分配方面是可接受的。

Sprint()连接可用于快速调试输出。 =>否则使用bytes。缓冲……WriteString

这是最快的解决方案,不需要 你首先需要知道或计算总的缓冲区大小:

var data []byte
for i := 0; i < 1000; i++ {
    data = append(data, getShortStringFromSomewhere()...)
}
return string(data)

根据我的基准测试,它比复制解决方案慢了20% (8.1ns / 追加而不是6.72ns),但仍然比使用bytes.Buffer快55%。

扩展cd1的答案: 你可以使用append()而不是copy()。 Append()提供了更大的预先准备,占用了更多的内存,但节省了时间。 我在你的上面又加了两个基准测试。 在本地运行

go test -bench=. -benchtime=100ms

在我的thinkpad T400s上,它产生:

BenchmarkAppendEmpty    50000000         5.0 ns/op
BenchmarkAppendPrealloc 50000000         3.5 ns/op
BenchmarkCopy           20000000        10.2 ns/op
package main

import (
  "fmt"
)

func main() {
    var str1 = "string1"
    var str2 = "string2"
    out := fmt.Sprintf("%s %s ",str1, str2)
    fmt.Println(out)
}

这是@cd1 (Go 1.8, linux x86_64)提供的实际版本的基准测试,修复了@icza和@PickBoy提到的错误。

字节。Buffer仅比通过+操作符直接串接快7倍。

package performance_test

import (
    "bytes"
    "fmt"
    "testing"
)

const (
    concatSteps = 100
)

func BenchmarkConcat(b *testing.B) {
    for n := 0; n < b.N; n++ {
        var str string
        for i := 0; i < concatSteps; i++ {
            str += "x"
        }
    }
}

func BenchmarkBuffer(b *testing.B) {
    for n := 0; n < b.N; n++ {
        var buffer bytes.Buffer
        for i := 0; i < concatSteps; i++ {
            buffer.WriteString("x")
        }
    }
}

计时:

BenchmarkConcat-4                             300000          6869 ns/op
BenchmarkBuffer-4                            1000000          1186 ns/op