一个快速拷贝被类型转换为 interface 的 struct 的方法

2020-12-23 12:36:29 +08:00
 fumeboy

方法是 从 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)
	}
}
1479 次点击
所在节点    Go 编程语言
5 条回复
cholerae
2020-12-23 12:52:56 +08:00
这代码明显有 bug 。可能运气好没有挂掉。
中间 copy 那一步,是没有带 write barrier 的。要搞也要用 typedmemmove 。
fumeboy
2020-12-23 12:58:53 +08:00
@cholerae 我自己也感觉会有 GC 的问题 .. typedmemmove 这些我去看一下
wellsc
2020-12-23 13:01:13 +08:00
零抽象
whitehack
2020-12-23 18:08:04 +08:00
只是浅拷贝吧?结构内的指针对象还是引用的同一个?
lance6716
2020-12-23 23:23:05 +08:00
ValueOf 然后再 Copy ?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/738182

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX