字符串拼接是字符的常见操作。在golang中,遇见了字符串拼接。作为一个长期的C程序员,我第一反应是:字符串拼接函数strcat,但发现golang并无字符串拼接函数。
我想起了最简单的方法,通过+操作符进行字符串拼接。
但我查了相关资料后发现:golang中的string类型也是只读且不可变的;因此,这种拼接字符串的方式会导致大量的string创建、销毁和内存分配。如果你拼接的字符串比较多的话,这显然不是一个正确的姿势。
然后,查找一些可行的方法。
(1)fmt.Sprintf():该方法内部使用 []byte 实现,不像直接运算符这种会产生很多临时的字符串,但是内部的逻辑比较复杂,有很多额外的判断,还用到了 interface,所以性能也不是很好。
(2)strings.Join():join会先根据字符串数组的内容,计算出一个拼接之后的长度,然后申请对应大小的内存,一个一个字符串填入,在已有一个数组的情况下,这种效率会很高,但是本来没有,去构造这个数据的代价也不小
(3)buffer.WriteString():可以当成可变字符使用,对内存的增长也有优化,如果能预估字符串的长度,还可以用 buffer.Grow() 接口来设置 capacity
(4)strings.Builder:golang拼接倡导的方法。
倡导尽量用strings.Builder方法,示例如下;
var build strings.Builder
build.WriteString("http://www.your_dsp.com/win?sid=")
build.WriteString(dsp.RequestId)
build.WriteString("&impid=")
build.WriteString(dsp.ImpInfo.Impid)
build.WriteString("&price={")
build.WriteString(fmt.Sprintf("%d", rsp.Bid.Price))
build.WriteString("}")
fmt.Println(build.String())
测试:
我自己写了个程序测试,发现:测试次数越大,fmt.Sprintf 的时间差距与strings.Builder的差距越大,代码如下:
func main(){ _, miniute, _ := time.Now().Clock() var dsp DspInfo = DspInfo{ "91b5e18c-014c-1000-e71a-3e9942b60043", "91b5e18c-014c-1000-e71a-3e9942b60043", time.Now().Format("2006010215"), int32(miniute), "5d0861a92e5f930fe8a66025"} i := 0 t1 := time.Now().UnixNano() for i < 10000000 { //combineURL("win" , &dsp, 100) var build strings.Builder build.WriteString("http://www.dsp.com") build.WriteString("/") //build.WriteString("http://www.dsp.com/") build.WriteString("win") build.WriteString("?sid=") build.WriteString(dsp.RequestId) build.WriteString("&impid=") build.WriteString(dsp.ImpId) //build.WriteString("&price={PRICE}&extdata=") build.WriteString("&price={PRICE}") build.WriteString("&extdata=") build.WriteString(dsp.TimeHour) build.WriteString(strconv.FormatInt(int64(dsp.Miniute), 10)) build.WriteString("_") build.WriteString(dsp.MmId) build.String() i++ } t2 := time.Now().UnixNano() i = 0 t3 := time.Now().UnixNano() for i < 10000000 { fmt.Sprintf("http://www.dsp.com/%s?sid=%s&impid=%s&price={PRICE}&extdata=%s%d_%s", "win", dsp.RequestId, dsp.ImpId, dsp.TimeHour, dsp.Miniute,dsp.MmId) i++ } t4 := time.Now().UnixNano() i = 0 t5 := time.Now().UnixNano() for i < 10000000 { var buff bytes.Buffer // 向buff中写入字符/字符串 buff.Write([]byte("http://www.dsp.com/")) buff.WriteString("win") buff.WriteString("?sid=") buff.WriteString(dsp.RequestId) buff.WriteString("&impid=") buff.WriteString(dsp.ImpId) buff.WriteString("&price={PRICE}") buff.WriteString("&extdata=") buff.WriteString(dsp.TimeHour) buff.WriteString(strconv.FormatInt(int64(dsp.Miniute), 10)) buff.WriteString("_") buff.WriteString(dsp.MmId) buff.String() i++ } t6 := time.Now().UnixNano() fmt.Println(t1, "\n", t2, "\n", t3, "\n", t4, "\n", t5, "\n", t6) fmt.Println("delta T1: ", t2 - t1, "\ndelta T2:", t4 - t3, "\ndelta T3:", t6 - t5) }