问题引入
在不同的包下定义了一些结构体 其所有字段都相同(内存布局完全一致),但是他们却属于不同的结构体
所以经常需要在这些结构体之间来回转换,主要实现思路有:
-
手写转换函数 逐个字段的赋值 字段很多的结构体书写费时费力
-
借助代码生成工具生成转换函数 本质上还是会
New一个新的结构体 -
先对结构体
UnMarshal再Marshal的方式完成转换 效率不高 -
深拷贝 使用
copier等库 -
原地类型强转 不涉及内存分配
举例
以下主要记录 原地类型转换的实现
// 来自 pkg f
type A struct {
B string
C int64
D string
}
// 来自 pkg g
type A struct {
B string
C int64
D string
}
实现一
针对同一片内存空间做类型转换
Unsafe概念 见 必知必会系列-Unsafe
func convert_1(a *f.A) *g.A {
return (*g.A)(*(*unsafe.Pointer)(unsafe.Pointer(&a)))
}
实现二
使用反射做转换
反射/接口原理 见 必知必会系列-interface
var (
gAType = reflect.TypeOf(g.A{})
)
func convert_2(a *f.A) *g.A {
return reflect.NewAt(gAType, unsafe.Pointer(a)).Interface().(*g.A)
}
注意点
上述的转换很高效,但是如果转换前后的结构体内存布局不一致,可能就会出现一些诡异的情况。
在真实使用过程中 需要确保两个结构体内存布局一致