24

让我们转换string[]byte

func toBytes(s string) []byte {
  return []byte(s) // What happens here?
}

这种铸造手术有多贵?是否执行复制?据我在 Go 规范中看到的:字符串表现得像字节切片但不可变,这至少应该涉及复制以确保后续切片操作不会修改我们的字符串s。反向对话会发生什么?对话是否[]byte <-> string涉及编码/解码,例如 utf8 <-> 符文?

4

3 回答 3

37

[]byte(s)不是强制转换而是转换。一些转换与强制转换相同,例如uint(myIntvar),它只是重新解释到位的。不幸的是,字符串到字节切片转换的情况并非如此。字节切片是可变的,字符串(准确地说是字符串值)不是。结果是正在制作的字符串的必要副本(内存分配+内容传输)。所以是的,在某些情况下它可能会很昂贵。

编辑:不执行编码转换。字符串(源)字节按原样复制到切片(目标)字节。

于 2013-01-17T06:59:38.440 回答
13

转换复制字节,但它也为堆上的 []byte 分配空间。在将字符串反复转换为 []byte 的情况下,您可以通过重用 []byte 和使用 copy 命令来节省内存管理时间。(参见http://golang.org/ref/spec#Appending_and_copying_slices以及关于使用字符串作为源的特殊情况。)

在转换和复制命令的两种情况下,复制本身都是一个直接字节的复制,它应该运行得非常快。我希望编译器能够生成某种 CPU 有效执行的重复移动指令。

反向转换,从字节切片中生成字符串,肯定涉及在堆上分配字符串。不变性属性迫使这一点。有时您可以通过使用 []byte 做尽可能多的工作然后在最后创建一个字符串来进行优化。bytes.Buffer 类型通常很有用。

现在追逐红鲱鱼,编码和 UTF-8 都不是问题。字符串和 []byte 都可以保存任意数据。副本不查看数据,它只是复制它。在说诸如字符串旨在包含 UTF-8 或鼓励使用 UTF-8 之类的内容时,请仔细选择单词。更准确的做法是简单地注意某些语言特性,例如 for 语句的范围子句,将字符串解释为 UTF-8。只需了解将字符串解释为 UTF-8 和不解释的内容。字符串中有非 UTF-8 并且需要按字节进行范围?没问题,只是不要使用范围子句。

s := "string"
for i := 0; i < len(s); i++ {
    b := s[i]
    // work with b
}

这是惯用的 Go。它没有气馁,也没有违反任何意图。它只是逐字节迭代字符串,这有时正是您想要做的。

于 2013-01-17T12:57:56.373 回答
0

作为对上述答案的补充,在最新的go 语言规范中,与数值类型之间的类型转换的特殊规则string声明如下:

特定规则适用于数字类型之间或字符串类型之间的(非常量)转换。这些转换可能会改变 x 的表示并产生运行时成本。所有其他转换仅更改类型,但不更改 x 的表示。

于 2022-02-02T05:28:29.100 回答