这不是一个编译器问题,而是一个语言规范问题。编译器有时会并且会做奇怪的事情-这里重要的是,无论编译器最终吐出来的机器代码是什么,它都遵循语言规范中列出的规则。

bytestring

将一个字节的切片转换为字符串类型会产生一个字符串,其连续字节是该切片的元素。

将字符串类型的值转换为字节类型的切片会产生一个切片,其连续元素是字符串的字节。

string

字符串是不可变的:一旦创建,就无法更改字符串的内容。

[]bytestring[]bytestring
package main

import (
    "fmt"
    "reflect"
    "unsafe"
)

func main() {
    a := "a"
    b := []byte(a)
    ah := (*reflect.StringHeader)(unsafe.Pointer(&a))
    fmt.Printf("a: %4s @ %#x\n", a, ah.Data)
    fmt.Printf("b: %v @ %p\n\n", b, b)

    c := []byte{'a'}
    d := string(c)
    dh := (*reflect.StringHeader)(unsafe.Pointer(&d))
    fmt.Printf("c: %v @ %p\n", c, c)
    fmt.Printf("d: %4s @ %#x\n", d, dh.Data)
}

输出如下:

a:    a @ 0x4c1ab2
b: [97] @ 0xc00002c008

c: [97] @ 0xc00002c060
d:    a @ 0x554e21
string[]byte[]bytestring

bcb[]bytea
package main

import (
    "fmt"
    "reflect"
    "unsafe"
)

func main() {
    a := "a"
    b := []byte(a)
    b[0] = 'b'
    ah := (*reflect.StringHeader)(unsafe.Pointer(&a))
    fmt.Printf("a: %4s @ %#x\n", a, ah.Data)
    fmt.Printf("b: %v @ %p\n\n", b, b)
}

输出:

a:    a @ 0x4c1ab2
b: [98] @ 0xc00002c008

Go Playground上观看此动作