不能假设[]byte(aString)转换得到的结果切片的容量和长度肯定一致

以下文章来源于Go 101 ,作者老貘

来看一个短小的程序:


package main 

import "fmt" 

func main() { 
  h := []byte("Hello") 
  hc := append(h, " C"...) 
  _ = append(h, " Go"...) 
  fmt.Printf("%sn", hc) 
  fmt.Printf("%d, %dn", cap(h), len(h)) 
} 

当使用标准Go编译器1.12版本编译此程序时,它的运行结果很可能正如很多Go程序员所料,如下所示:


Hello C 
5, 5 

但是当此程序使用标准Go编译器1.11版本编译时,它的运行结果却如下所示:


Hello G 
8, 5 

标准Go编译器1.11版本的bug?否。事实上,标准Go编译器的两个版本对字符串到字节切片的转换的实现都是正确的,因为Go官方文档并没有强制要求将字符串转换到字节切片的结果的容量和长度一定要相等。对于标准Go编译器1.11版本来说,在上面这个程序中的转换[]byte("Hello")的结果切片的容量为8,长度为5,所以这导致两个append调用的结果切片可以共享底层字节序列。第二个append调用中添加的字节覆盖了第一个append调用中添加的字节。

所以上面这个程序的运行结果是依赖于具体编译器和编译器版本实现的。

为了防止出现非我们所料的运行结果,我们应该将上述程序中的第一个append调用中的基础切片实参改为三下标子切片形式,如下:


package main 

import "fmt" 

func main() { 
  h := []byte("Hello") 
  hc := append(h[:len(h):len(h)], " C"...) 
  _ = append(h, " Go"...) 
  fmt.Printf("%sn", hc) 
  fmt.Printf("%d, %dn", cap(h), len(h)) 
} 

这样,更改后的程序(使用标准Go编译器1.11版本编译时)的运行结果:


Hello C 
8, 5 

从字符串到码点切片[]rune的转换的情况也是类似的。

2