[]字节(字符串)有多贵?

dem*_*emi 19 performance type-conversion go

让我们转换string[]byte:

func toBytes(s string) []byte {
  return []byte(s) // What happens here?
}
Run Code Online (Sandbox Code Playgroud)

这个演员阵营有多贵?正在进行复制吗?就我在Go规范中看到的那样:字符串的行为类似于字节切片但是不可变,这至少应该涉及复制以确保后续切片操作不会修改我们的字符串s.反向对话会发生什么?[]byte <-> string会话是否涉及编码/解码,如utf8 < - >符文?

zzz*_*zzz 26

[]byte(s)不是演员而是转换.有些转换是一样的铸像uint(myIntvar),刚刚重新诠释位到位.不幸的是,这不是字符串到字节切片转换的情况.字节切片是可变的,字符串(字符串值要精确)不是.结果是正在进行的字符串的必要副本(mem alloc + content transfer).所以是的,在某些情况下它可能代价高昂.

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

  • 《Go 编程》一书声称:“‘[]byte(string)’ 转换非常快 (O(1)),因为在幕后,‘[]byte` 可以简单地引用字符串的不需要复制的底层字节。反向转换“string([]byte);”也是如此,底层字节不会被复制,因此转换时间复杂度为 O(1)。”* 所以看来这个声明是不正确。 (6认同)
  • 那太伤心了. (3认同)
  • FWIW,有一个[公开问题](http://code.google.com/p/go/issues/detail?id=2205)请求一个功能,如果在`[]字节之后永远不修改结果字节数组( s)`转换,它将使用字符串提供的底层数组而不是复制.似乎表面上有用的优化. (3认同)
  • 来自http://golang.org/ref/spec#String_types:“字符串的元素具有字节类型,可以使用通常的索引操作进行访问。”。所以没有UTF-8,没有符文。字符串是一个编号的字节序列,_any_ 字节。OTOH,许多 stdlib 函数仅适用于 UTF-8 编码的字符串。 (2认同)
  • @demi字符串的表示形式是一种字节数组.但是,字符串显然包含utf-8编码:应用于字符串的`range`语句解码utf-8并返回代码点.[参见规范](http://golang.org/ref/spec#For_statements). (2认同)

Son*_*nia 12

转换复制字节,但它也为堆上的[]字节分配空间.如果重复将字符串转换为[]字节,则可以通过重用[]字节并使用copy命令来节省内存管理时间.(请参阅http://golang.org/ref/spec#Appending_and_copying_slices以及有关使用字符串作为源的特殊情况.)

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

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

现在追逐红鲱鱼,编码和UTF-8不是问题.字符串和[]字节都可以保存任意数据.副本不会查看数据,只是复制它.当说字符串之类的内容旨在包含UTF-8或鼓励这样做时,请仔细选择单词.简单地注意一些语言特性(例如for语句的range子句)字符串解释为UTF-8 更为准确.只需了解将字符串解释为UTF-8的内容以及什么不是.在字符串中使用非UTF-8并且需要按字节顺序排列吗?没问题,只是不要使用range子句.

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

这是惯用的Go.它并没有气馁,也没有任何意图.它只是按字节顺序遍历字符串,这有时就是你想做的事情.