一尘不染

如何在Go中有效地串联字符串

go

在Go中,a string是原始类型,这意味着它是只读的,对其的每次操作都会创建一个新的字符串。

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

天真的方法是:

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

但这似乎不是很有效。


阅读 523

收藏
2020-07-02

共1个答案

一尘不染

新方法:

在Go 1.10+中strings.Builder,这里是。

生成器用于使用Write方法有效地构建字符串。它最大程度地减少了内存复制。零值可以使用了。

与几乎相同bytes.Buffer。

package main

import (
    "strings"
    "fmt"
)

func main() {
    // ZERO-VALUE:
    //
    // It's ready to use from the get-go.
    // You don't need to initialize it.
    var str strings.Builder

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

    fmt.Println(str.String())
}

注意

  • 不要复制StringBuilder值,因为它会缓存基础数据。
  • 如果要共享StringBuilder值,请使用指向它的指针。

支持的接口

正在考虑现有接口的情况下实现StringBuilder的方法。这样您就可以在代码中轻松切换到新的Builder类型。

与bytes.Buffer的差异

  • 它只能增长或重置。

  • 它具有内置的copyCheck机制,可防止意外复制它:

  • func (b *Builder) copyCheck() { … }

  • 在中bytes.Buffer,人们可以像这样访问基础字节:(*Buffer).Bytes()。

  • strings.Builder 可以防止此问题。

  • 有时,这不是问题,而是需要的。
  • 例如:对于将字节传递给io.Readeretc 时的偷窥行为。

旧方法:

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

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)时间内完成的。

2020-07-02