如何在Go语言中克隆一个strings.Builder对象?

3
Go编程语言的标准库提供了一个名为strings.Builder的结构体,它允许通过重复连接字符串的方式以高效的方式轻松构建字符串,类似于C#或Java的StringBuilder
在Java中,我会使用StringBuilder的构造函数来“克隆”对象,就像这样:
StringBuilder newBuffer = new StringBuilder(oldBuffer.toString());

在 Go 中,我只能看到以下两行代码的方式:
newBuffer := strings.Builder{}
newBuffer.WriteString(oldBuffer.String())

并且没有其他.Clone()初始化方法(也许我还没有找到)。

是否有比我提出的更简洁的方式?


2
当然。添加您自己的函数,其中包含克隆字符串构建器所需的两行代码,然后调用者只需要一行代码即可进行克隆。 - Gavin
WriteString方法可能会失败,因此它返回两个值,一个是字符串,一个是错误。我不确定C#或Java如何实现这些,但我想象如果它们也可能失败,则需要某种异常处理。 - Grizzle
1
@Grizzle WriteString方法声明为返回错误,以便StringBuilder满足io.StringWriter接口,而不是因为WriteString可能会失败。不需要进行错误检查。 - Charlie Tumahai
@Gavin 当然,那将是最后的选择...我只是想检查是否有其他更标准/惯用的形式我错过了。对于我的好奇心打扰你,我很抱歉! - Daniel Gray
如果您查看builder.go的源代码,您会发现许多函数仅有3行(包括复制此字符串构建器的函数,当您计算'return...'时)。您是否认为应该在使用这些其他2行函数集的所有位置都只编写它们?(这只是一些思考的食物) - Daniel Gray
1个回答

5

为了满足好奇心而过分详细...

考虑文档后,以下是您的主要问题:

  1. 从Builder中读取数据的唯一导出方法是Builder.String方法。
  2. 在操作Builder值后复制它是不安全的。

让我们来看看这个版本:

newBuffer := strings.Builder{}
newBuffer.WriteString(oldBuffer.String())

我的第一个想法是为什么这样做不可取,因为 Builder 内部使用的是字节切片(可变数据类型),并返回字符串(不可变数据类型)。尽管字符串的底层表示与字节切片相同,但由于这种可变性规则,将其转换为字符串需要进行复制。这意味着当你将字符串写入新缓冲区时,你已经进行了第二次复制,而你的任务直觉上只需要一次复制。
实际上,查看 源代码,我们会发现这个假设是错误的:
func (b *Builder) String() string {
    return *(*string)(unsafe.Pointer(&b.buf))
}

使用unsafe包,strings包基本上直接将缓冲区([]byte)“黑客化”成一个string。再次强调,这些数据类型在内存级别上是相同的: 字符串或切片开头的指针和描述字符串或切片有多少字节长的指针偏移量。这些数据类型只是头文件,因此没有复制缓冲区。

这会创建一个不舒服的情况,你有一个应该是不可变的字符串,但你仍然有一个字节切片在某个地方可以改变这些底层字节。毕竟,这个包叫做unsafe,这正是为什么的一个很好的例子。

因为 strings.Builder 是纯粹的“构建器”,即它只能创建字符串的新部分,而不能修改已经编写的数据,我们仍然可以获得语言所“保证”的字符串的不可变性。唯一打破这个规则的方法是访问 Builder 的内部 buf,但由于该 字段未公开, 您需要自己使用 unsafe 来访问它。

摘要:

你提出的直接方法,虽然可能比人们希望的多了一行(或两行),但它是做到这一点的明确和正确的方法。即使您使用 Go 的更复杂的功能,如 unsafereflect,它已经足够高效。

希望这些信息对你有所帮助。以下是您代码的唯一建议修改:

// clone the builder contents. this is fast.
newBuffer := strings.Builder{}
newBuffer.WriteString(oldBuffer.String())

谢谢!我猜测底层的字节切片在strings.Builder{}之外并不是真正可访问的,所以.String()方法内部的不安全调用可能并不是什么大问题。同时很高兴知道它不会做两次拷贝而不是一次。写得很好,再次感谢! - Daniel Gray

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接