Golang Go语言中一个快速拷贝被类型转换为 interface 的 struct 的方法

发布于 1周前 作者 songsunli 来自 Go语言

Golang Go语言中一个快速拷贝被类型转换为 interface 的 struct 的方法

方法是 从 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)
	}
}

更多关于Golang Go语言中一个快速拷贝被类型转换为 interface 的 struct 的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

6 回复

这代码明显有 bug 。可能运气好没有挂掉。
中间 copy 那一步,是没有带 write barrier 的。要搞也要用 typedmemmove 。

更多关于Golang Go语言中一个快速拷贝被类型转换为 interface 的 struct 的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我自己也感觉会有 GC 的问题 … typedmemmove 这些我去看一下

只是浅拷贝吧?结构内的指针对象还是引用的同一个?

ValueOf 然后再 Copy ?

在Go语言中,当你有一个结构体(struct)被类型转换为interface{}类型后,直接进行拷贝可能会变得不那么直观,因为interface{}是一个空接口,可以表示任意类型。然而,你仍然可以通过一些技巧来实现快速拷贝。

一种常见的方法是使用类型断言(type assertion)将interface{}转换回原始的结构体类型,然后再进行拷贝。例如:

package main

import (
	"fmt"
)

type MyStruct struct {
	Field1 int
	Field2 string
}

func main() {
	original := MyStruct{Field1: 1, Field2: "hello"}
	var i interface{} = original

	// 类型断言
	if copied, ok := i.(MyStruct); ok {
		// 现在copied是MyStruct类型的一个拷贝(实际上是值传递)
		fmt.Printf("Copied: %+v\n", copied)
	} else {
		fmt.Println("Type assertion failed")
	}
}```


在这个例子中,我们首先将`MyStruct`类型的变量。`注意original,`这里的赋值拷贝给一个实际上是`值interface传递{}直接,`类型即类型的断言`变量更copied`慢`i且是`更复杂`。。original然后通过
回到顶部