方法是 从 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)
}
}
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.