将 []byte
转换为 string
的首选方法是这样的:
var b []byte
// fill b
s := string(b)
在此代码中,字节 slice 被复制,这在性能很重要的情况下可能是个问题。
当性能很关键时,可以考虑执行不安全的转换:
var b []byte
// fill b
s := *(*string)(unsafe.Pointer(&b))
我的问题是:使用不安全转换会出现什么问题?我知道 string
应该是不可变的,如果我们更改 b
,s
也会更改。仍然:那又怎样?可能发生的都是坏事吗?
最佳答案
修改语言规范保证不可变的东西是叛国行为。
由于规范保证 string
是不可变的,因此允许编译器生成缓存其值的代码,并基于此进行其他优化。您不能以任何正常方式更改 string
的值,并且如果您诉诸肮脏的方式(如 package unsafe
)仍然这样做,您将失去所有保证由规范提供,并继续使用修改后的 string
,您可能会随机遇到“错误”和意想不到的事情。
例如,如果您使用 string
作为 map 中的键,并且在将其放入 map 后更改 string
,您可能无法找到 map 中的关联值使用 string
的原始值或修改后的值(这取决于实现)。
为了证明这一点,请看这个例子:
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)
}
}
输出(在 Go Playground 上尝试):
Before: map[hi:999]
After: map[bi:<nil>]
But it's there: 999 999
Now it's GONE: 0 0
But still there, just in a different bucket: bi 999
起初,我们只看到一些奇怪的结果:简单的 Println()
无法找到它的值。它看到了一些东西(找到了键),但值显示为 nil
这甚至不是值类型 int
的有效值(int< 的零值
是 0
)。
如果我们将 map 变大(我们添加 1000 个元素), map 的内部数据结构将被重组。在此之后,我们甚至无法通过使用适当的键明确请求它来找到我们的值(value)。它仍然在 map 中迭代我们找到它的所有键值对,但由于哈希码随着 string
值的变化而变化,很可能它是在与之前不同的桶中搜索的它在哪里(或它应该在哪里)。
另请注意,使用 unsafe
包的代码现在可能会像您预期的那样工作,但相同的代码可能会在未来(或旧)版本的 Go 中以完全不同的方式工作(这意味着它可能会中断) “导入不安全的包可能是不可移植的,并且不受 Go 1 兼容性指南的保护”。
您也可能会遇到意外错误,因为修改后的 string
可能会以不同的方式使用。有人可能只复制字符串标题,有人可能复制其内容。看这个例子:
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
创建了2个新的局部变量s2
和s3
,s2
通过复制字符串头来初始化s
和 s3
使用新的 string
值(新字符串 header )初始化,但内容相同。现在,如果您修改原始 s
,您会期望在一个正确的程序中将新字符串与原始字符串进行比较,您会得到相同的结果,无论是 true
还是 false
(基于值是否被缓存,但应该相同)。
但输出是(在 Go Playground 上尝试):
hi hi hi
true
false
关于string - 在 go 中使用从 []byte 到 string 的不安全转换可能产生的后果是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33952378/