如何解决使用反射和不安全包复制切片
我知道使用 unsafe
包的 golang 是不安全的,但我这样做只是为了教育目的。
思路是复制一个结构体的slice字段,用reflect包和unsafe.pointer复制,修改并用新的slice替换原来的slice。
看起来新切片已创建并且具有正确的容量/长度,并且它包含一个 GoodForSale
类型的实例。但是该实例的所有字段(名称、价格和数量)都有错误的值。所以我想我在指针和获取垃圾数据方面做错了:
package main
import (
"fmt"
"reflect"
"unsafe"
)
type GoodForSale struct {
Name string
Price int
Qnty int
}
type Lead struct {
ID int
Name string
ContactName string
Budget int
Items []GoodForSale
DateTime string
Status int
Win bool
}
func main() {
lead := &Lead{
ID: 41,Name: "Phone",ContactName: "John Smith",Budget: 30000,Items: []GoodForSale{
{
Name: "Iphone 6",Price: 100,Qnty: 3,},DateTime: "12.08.2020 11:23:10",Status: 150,Win: false,}
//Change Items
pt1 := unsafe.Pointer(&lead.Items)
copyItems := &reflect.SliceHeader{
Data: uintptr(pt1),Cap: cap(lead.Items),Len: len(lead.Items),}
items := *(*[]GoodForSale)(unsafe.Pointer(copyItems))
fmt.Println(items[0].Name)
}
我好像遗漏了一些关于指针如何在这里工作的信息。但是我怎样才能使这个想法正确?
这是一个去游乐场网址:https://play.golang.org/p/SKtJWe9RVEU
解决方法
问题出在这里:
pt1 := unsafe.Pointer(&lead.Items) // pointer the slice,a.k.a "slice header"
copyItems := &reflect.SliceHeader{
Data: uintptr(pt1),// trying to use it as pointer to the actual data.
“数据”需要一个指向实际数据开始位置的指针,但您提供的是一个指向切片本身的指针。
这是获取切片数据指针的正确方法:
pt1 := unsafe.Pointer(&lead.Items[0]) // pointer to the first element referenced by the slice
请注意,如果 len(lead.Items) == 0
,这将导致恐慌。在这种情况下,您应该使用 unsafe.Pointer(nil)
。
您还可以通过将原始切片转换为 reflect.SliceHeader
来从原始切片中获取数据指针(以及 len 和 cap),如下所示:
copyHeader := *(*reflect.SliceHeader)(unsafe.Pointer(&lead.Items))
items := *(*[]GoodForSale)(unsafe.Pointer(©Header))
但在这一点上,我们基本上只是制作了一个复杂且“不安全”的版本:
items := lead.Items
,
基于 Hymns For Disco 的输入,通过向指针提供切片元素而不是整个切片来修改您的代码。
package main
import (
"fmt"
"reflect"
"unsafe"
)
type GoodForSale struct {
Name string
Price int
Qnty int
}
type Lead struct {
ID int
Name string
ContactName string
Budget int
Items []GoodForSale
DateTime string
Status int
Win bool
}
func main() {
lead := &Lead{
ID: 41,Name: "Phone",ContactName: "John Smith",Budget: 30000,Items: []GoodForSale{
{
Name: "Iphone 6",Price: 100,Qnty: 3,},DateTime: "12.08.2020 11:23:10",Status: 150,Win: false,}
pt1 := unsafe.Pointer(&lead.Items[0])
copyHeader := *(*reflect.SliceHeader)(unsafe.Pointer(&lead.Items))
items := *(*[]GoodForSale)(unsafe.Pointer(©Header))
//items := *(*[]GoodForSale)(unsafe.Pointer(copyItems))
fmt.Println(pt1)
fmt.Println(items[0].Name)
}
输出:
0xc00000c080
Iphone 6
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。