一尘不染

如何在go中有效地连接字符串

go

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

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

天真的方法是:

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

但这似乎不是很有效。


阅读 349

收藏
2021-10-18

共2个答案

一尘不染

新方法:

从 Go 1.10 开始,有一种strings.Builder类型

旧方式:

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

2021-10-18
一尘不染

在 Go 1.10+ 中strings.Builder这里有

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 sb strings.Builder

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

    fmt.Println(sb.String())
}

单击以在操场上查看此内容


支持的接口

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


与 bytes.Buffer 的区别

  • 它只能增长或重置。

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

func (b *Builder) copyCheck() { ... }

  • bytes.Buffer,一个可以访问这样的底层字节:(*Buffer).Bytes()

  • strings.Builder 防止这个问题。

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

  • bytes.Buffer.Reset() 倒带并重用底层缓冲区,而strings.Builder.Reset() 不会,它分离缓冲区。


笔记

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