为了账号安全,请及时绑定邮箱和手机立即绑定

golang是如何实现[]byte和string之间的转换的?

golang是如何实现[]byte和string之间的转换的?

Go
FFIVE 2022-06-06 15:52:10
我无法通过检查生成的程序集得到答案:    {        a := []byte{'a'}        s1 := string(a)        a[0] = 'b'        fmt.Println(s1) // a    }    {        a := "a"        b := []byte(a)        b[0] = 'b'        fmt.Println(a) // a    }为什么观察到的行为会发生?是否有关于 go 如何解释这些代码行的描述?Go 编译器对类型转换做了什么?
查看完整描述

1 回答

?
动漫人物

TA贡献1815条经验 获得超10个赞

这与其说是编译器问题,不如说是语言规范问题。编译器有时可以而且会做一些奇怪的事情——这里重要的是编译器最终输出的任何机器代码,它都遵循语言规范中规定的规则。

正如评论中所提到的,语言规范定义了byte切片与string以下类型的转换:

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

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

为了理解示例的行为,您还必须阅读规范中string的类型定义:

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

因为[]byte 可变的,所以在与string. 这可以通过打印对象的第 0 个元素的地址[]byte和指向对象中数据的第一个元素的指针来验证string。这是一个示例(和一个Go Playground 版本):

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相同且不重叠。因此,不期望值的更改[]byte会以任何方式影响string值。


好的,从技术上讲,结果不必是这种方式,因为我没有在示例中对bor的值进行任何更改c。从技术上讲,编译器可以采取捷径,简单地称为blength=1[]byte从与a. 但是,如果我改为这样做,则不允许这种优化:


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中查看此操作。


查看完整回答
反对 回复 2022-06-06
  • 1 回答
  • 0 关注
  • 145 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信