Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
String 在go中使用从[]字节到字符串的不安全转换可能产生什么后果?_String_Pointers_Go_Unsafe - Fatal编程技术网

String 在go中使用从[]字节到字符串的不安全转换可能产生什么后果?

String 在go中使用从[]字节到字符串的不安全转换可能产生什么后果?,string,pointers,go,unsafe,String,Pointers,Go,Unsafe,将[]字节转换为字符串的首选方法如下: var b []byte // fill b s := string(b) 在这个代码中,字节片被复制,这在性能很重要的情况下可能是一个问题 当性能是关键时,可以考虑执行不安全转换: var b []byte // fill b s := *(*string)(unsafe.Pointer(&b)) 我的问题是:使用不安全转换时会出现什么问题?我知道string应该是不可变的,如果我们改变b,s也会改变。还有:那又怎样?这一切都是坏事吗?修改

[]字节
转换为
字符串
的首选方法如下:

var b []byte
// fill b
s := string(b)
在这个代码中,字节片被复制,这在性能很重要的情况下可能是一个问题

当性能是关键时,可以考虑执行不安全转换:

var b []byte
// fill b
s :=  *(*string)(unsafe.Pointer(&b))

我的问题是:使用不安全转换时会出现什么问题?我知道
string
应该是不可变的,如果我们改变
b
s
也会改变。还有:那又怎样?这一切都是坏事吗?

修改语言规范保证不可变的东西是叛国行为

由于规范保证
string
s是不可变的,因此允许编译器生成缓存其值的代码,并在此基础上进行其他优化。您不能以任何正常方式更改
字符串
s的值,如果您仍然使用肮脏的方式(如package
unsafe
)进行更改,您将失去规范提供的所有保证,继续使用修改后的
字符串
s,您可能会随机遇到“bug”和意外情况

例如,如果将
字符串
用作映射中的键,并在将其放入映射后更改
字符串
,则可能无法使用
字符串
的原始值或修改值在映射中找到关联值(这取决于实现)

要演示这一点,请参见以下示例:

m := map[string]int{}
b := []byte("hi")
s := *(*string)(unsafe.Pointer(&b))
m[s] = 999

fmt.Println("Before:", m)

b[0] = 'b'
fmt.Println("After:", m)

fmt.Println("But it's there:", m[s], m["bi"])

for i := 0; i < 1000; i++ {
    m[strconv.Itoa(i)] = i
}
fmt.Println("Now it's GONE:", m[s], m["bi"])
for k, v := range m {
    if k == "bi" {
        fmt.Println("But still there, just in a different bucket: ", k, v)
    }
}
b := []byte{'h', 'i'}
s := *(*string)(unsafe.Pointer(&b))

s2 := s                 // Copy string header
s3 := string([]byte(s)) // New string header but same content
fmt.Println(s, s2, s3)
b[0] = 'b'

fmt.Println(s == s2)
fmt.Println(s == s3)
我们使用
s
创建了两个新的局部变量
s2
s3
s2
通过复制
s
的字符串头进行初始化,
s3
使用一个新的
字符串
值(新字符串头)进行初始化,但内容相同。现在,如果您修改原始的
s
,您将期望在正确的程序中,将新字符串与原始字符串进行比较,您将得到相同的结果,无论是
true
还是
false
(基于是否缓存了值,但应该是相同的)

但输出是(在上尝试):


切勿使用不安全的工具。性能从来没有那么重要。
b := []byte{'h', 'i'}
s := *(*string)(unsafe.Pointer(&b))

s2 := s                 // Copy string header
s3 := string([]byte(s)) // New string header but same content
fmt.Println(s, s2, s3)
b[0] = 'b'

fmt.Println(s == s2)
fmt.Println(s == s3)
hi hi hi
true
false