在Go中,字符串是一种基本类型,这意味着它是只读的,对它的每次操作都会创建一个新字符串。
如果我想多次连接字符串而不知道结果字符串的长度,最好的方法是什么?
最天真的做法是:
var s string
for i := 0; i < 1000; i++ {
s += getShortStringFromSomewhere()
}
return s
但这似乎不是很有效。
在Go中,字符串是一种基本类型,这意味着它是只读的,对它的每次操作都会创建一个新字符串。
如果我想多次连接字符串而不知道结果字符串的长度,最好的方法是什么?
最天真的做法是:
var s string
for i := 0; i < 1000; i++ {
s += getShortStringFromSomewhere()
}
return s
但这似乎不是很有效。
当前回答
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))
}
其他回答
s := fmt.Sprintf("%s%s", []byte(s1), []byte(s2))
新方法:
从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)时间内完成。
使用内存分配统计信息的基准测试结果。在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
这是@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