在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
但这似乎不是很有效。
当前回答
我最初的建议是
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
其他回答
您可以创建一个大的字节片,并使用字符串片将短字符串的字节复制到其中。在“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()将其再次转换为字符串。
goutils。JoinBetween
func JoinBetween(in []string, separator string, startIndex, endIndex int) string {
if in == nil {
return ""
}
noOfItems := endIndex - startIndex
if noOfItems <= 0 {
return EMPTY
}
var builder strings.Builder
for i := startIndex; i < endIndex; i++ {
if i > startIndex {
builder.WriteString(separator)
}
builder.WriteString(in[i])
}
return builder.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
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
我最初的建议是
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