方法是 从 interface 获取 struct 的地址, 然后将 struct 转成 []byte, 拷贝后再将 []byte 转成 struct
package main_test
import (
"fmt"
"reflect"
"testing"
"unsafe"
)
type beCopy struct {
value int
}
type emptyInterface struct {
typ *struct{}
word unsafe.Pointer
}
type slice struct {
array unsafe.Pointer
len int
cap int
}
func Copy(v interface{}) interface{} {
// 传进来的是一个 struct, 但是类型转换为了 interface
// 目的是拷贝这个 struct
// 因为 interface 本质是一个携带了原来类型信息的指针
// 所以直接 值传递 拷贝是不行的, 值传递拷贝只能再得到一个这样的指针
var t = reflect.TypeOf(v)
var length = int(t.Size())
var vslice = []byte{}
// 所以这里将 struct 的地址替换到 slice 的地址位, 使 vslice 指向的一串内存就是 struct 的内存
(*slice)(unsafe.Pointer(&vslice)).array = (*emptyInterface)(unsafe.Pointer(&v)).word
(*slice)(unsafe.Pointer(&vslice)).len = length
(*slice)(unsafe.Pointer(&vslice)).cap = length
vvslice := make([]byte, length) // 再创建一个 slice
copy(vvslice, vslice) // 将 struct 的内存拷贝到新的 slice
vv := v // 拷贝一个 interface 指针
((*emptyInterface)(unsafe.Pointer(&vv))).word = (*slice)(unsafe.Pointer(&vvslice)).array // 将 新 slice 的内存地址 替换为结构体指针指向的地址
return vv // 返回深拷贝后的 interface 指针
// 大致意思就是,将 struct 转成 []byte, 拷贝后再将 []byte 转成 struct
}
func TestCopy(t *testing.T){
b := beCopy{value: 3}
d := Copy(b)
b.value++
e := Copy(b)
fmt.Println(b,d,e)
}
func BenchmarkCopy(b *testing.B) {
c := beCopy{value: 3}
for i := 0; i < b.N; i++ {
Copy(c)
}
}
1
cholerae 2020-12-23 12:52:56 +08:00 1
这代码明显有 bug 。可能运气好没有挂掉。
中间 copy 那一步,是没有带 write barrier 的。要搞也要用 typedmemmove 。 |
3
wellsc 2020-12-23 13:01:13 +08:00 via iPhone
零抽象
|
4
whitehack 2020-12-23 18:08:04 +08:00
只是浅拷贝吧?结构内的指针对象还是引用的同一个?
|
5
lance6716 2020-12-23 23:23:05 +08:00 via Android
ValueOf 然后再 Copy ?
|