使用反射和不安全包复制切片
Copy slice with reflect and unsafe package
我知道使用 unsafe
golang 包是不安全的,但我这样做只是为了教育目的。
思路是复制一个structure的slice字段,用reflect包复制,unsafe.pointer,修改替换原来的slice。
看起来新切片已创建并且具有正确的 capacity/length,并且它包含 GoodForSale
类型的实例。但是该实例的所有字段(名称、价格和数量)都有错误的值。所以我想我在使用指针和获取 garbade 数据时做错了什么:
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)
}
我似乎遗漏了一些有关指针在这里如何工作的信息。但是我怎样才能使这个想法正确呢?
这是一个围棋游戏场url: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
我知道使用 unsafe
golang 包是不安全的,但我这样做只是为了教育目的。
思路是复制一个structure的slice字段,用reflect包复制,unsafe.pointer,修改替换原来的slice。
看起来新切片已创建并且具有正确的 capacity/length,并且它包含 GoodForSale
类型的实例。但是该实例的所有字段(名称、价格和数量)都有错误的值。所以我想我在使用指针和获取 garbade 数据时做错了什么:
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)
}
我似乎遗漏了一些有关指针在这里如何工作的信息。但是我怎样才能使这个想法正确呢?
这是一个围棋游戏场url: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