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

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

最天真的做法是:

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

但这似乎不是很有效。


当前回答

我最初的建议是

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

其他回答

使用内存分配统计信息的基准测试结果。在github检查基准代码。

使用字符串。构建器来优化性能。

go test -bench . -benchmem
goos: darwin
goarch: amd64
pkg: github.com/hechen0/goexp/exps
BenchmarkConcat-8                1000000             60213 ns/op          503992 B/op          1 allocs/op
BenchmarkBuffer-8               100000000               11.3 ns/op             2 B/op          0 allocs/op
BenchmarkCopy-8                 300000000                4.76 ns/op            0 B/op          0 allocs/op
BenchmarkStringBuilder-8        1000000000               4.14 ns/op            6 B/op          0 allocs/op
PASS
ok      github.com/hechen0/goexp/exps   70.071s

如果你有一个字符串切片,你想要有效地转换成一个字符串,那么你可以使用这种方法。否则,看看其他答案。

在strings包中有一个名为Join的库函数: http://golang.org/pkg/strings/#Join

看看Join的代码,可以看到Kinopiko写的类似于Append函数的方法:https://golang.org/src/strings/strings.go#L420

用法:

import (
    "fmt";
    "strings";
)

func main() {
    s := []string{"this", "is", "a", "joined", "string\n"};
    fmt.Printf(strings.Join(s, " "));
}

$ ./test.bin
this is a joined string
s := fmt.Sprintf("%s%s", []byte(s1), []byte(s2))

strings. join()来自"strings"包

如果你有一个类型不匹配(比如如果你试图连接一个int和一个字符串),你做RANDOMTYPE(你想改变的东西)

EX:

package main

import (
    "fmt"
    "strings"
)

var intEX = 0
var stringEX = "hello all you "
var stringEX2 = "people in here"


func main() {
    s := []string{stringEX, stringEX2}
    fmt.Println(strings.Join(s, ""))
}

输出:

hello all you people in here

您可以创建一个大的字节片,并使用字符串片将短字符串的字节复制到其中。在“Effective Go”中给出了一个函数:

func Append(slice, data[]byte) []byte {
    l := len(slice);
    if l + len(data) > cap(slice) { // reallocate
        // Allocate double what's needed, for future growth.
        newSlice := make([]byte, (l+len(data))*2);
        // Copy data (could use bytes.Copy()).
        for i, c := range slice {
            newSlice[i] = c
        }
        slice = newSlice;
    }
    slice = slice[0:l+len(data)];
    for i, c := range data {
        slice[l+i] = c
    }
    return slice;
}

然后,当操作完成时,在大字节片上使用string()将其再次转换为字符串。