总共三个部分,第一个部分Copy函数,以及它的弊端,第二部分DeepCopy,第三部分IgnoreEmpty,第四部分Converters
copier没有什么复杂的操作,可以做文章只有Option这个来说,所以后面几乎都是围绕这个来说的
shell
go get github.com/jinzhu/copier参考
Copy
- 调用同名方法为字段赋值;
- 以源对象字段为参数调用目标对象的方法,从而为目标对象赋值(当然也可以做其它的任何事情);
- 将切片赋值给切片(可以是不同类型哦);
- 将结构体追加到切片中。
以上部分是抄这里知乎文章,详细功能也在里面
go
type SC struct {
C uint8
}
type Map1 struct {
M map[string]int32
A []int32
C *SC
}
func main() {
var src = Map1{map[string]int32{"C:": 3, "d": 4}, []int32{9, 8}, &SC{32}}
var dst1 = Map1{}
fmt.Printf("src %+v\ndst %+v\n", src, dst1)
copier.Copy(&dst1, src)
dst1.M["F"] = 5
dst1.M["g"] = 6
dst1.M["C"] = 999
dst1.A[0] = 7
dst1.C.C = 27
fmt.Printf("src %+v\ndst %+v\n", src, dst1)
}
//src {M:map[C::3 d:4] A:[9 8] C:0xc0000180e0}
//dst {M:map[] A:[] C:<nil>}
//src {M:map[C:999 C::3 F:5 d:4 g:6] A:[7 8] C:0xc0000180e0}
//dst {M:map[C:999 C::3 F:5 d:4 g:6] A:[7 8] C:0xc0000181d8}
// 这里可以看出,对于引用型变量,使用Copy会直接将变量的地址进行Copy,而不是将实际的值,所以需要DeepCopyDeepCopy
需要注意的是,操作的结构体的成员变量首字母必须大写,不然由于copier无法访问这些结构体变量,从而无法深拷贝成功
go
type SC struct {
C uint8
}
type Map1 struct {
M map[string]int32
A []int32
C *SC
}
func main() {
var src = Map1{map[string]int32{"C:": 3, "d": 4}, []int32{9, 8}, &SC{32}}
var dst1 = Map1{}
fmt.Printf("src %+v\ndst %+v\n", src, dst1)
copier.CopyWithOption(&dst1, src, copier.Option{DeepCopy: true})
//copier.Copy(&dst1, src)
dst1.M["F"] = 5
dst1.M["g"] = 6
dst1.M["C"] = 999
dst1.A[0] = 7
dst1.C.C = 27
fmt.Printf("src %+v\ndst %+v\n", src, dst1)
}
//src {M:map[C::3 d:4] A:[9 8] C:0xc0000180e0}
//dst {M:map[] A:[] C:<nil>}
//src {M:map[C::3 d:4] A:[9 8] C:0xc0000180e0}
//dst {M:map[C:999 C::3 F:5 d:4 g:6] A:[7 8] C:0xc000018210}
// 使用DeepCopy会将其中的值进行拷贝,而不是复制地址IgnoreEmpty
就是将src复制给dst,如果src的某个成员变量为空,那么就不将其复制过去,保持dst原来的值
go
type ArrTC struct {
Name [2]string
C *ArrTC
}
type ArrT struct {
A [3]int32
S []int32
E []int32
C string
V string
M map[string]int32
AC ArrTC
s bool
}
func main() {
var src = ArrT{
[3]int32{9, 10, 0},
[]int32{12, 0},
[]int32{},
"",
"val",
map[string]int32{"A:": 1, "b": 0},
ArrTC{},
true,
}
var dst = ArrT{
[3]int32{1, 2, 3},
[]int32{4, 5, 6, 7},
[]int32{9, 10},
"char",
"ha",
map[string]int32{"C:": 3, "b": 4, ".": 0},
ArrTC{[2]string{"Y", "Z"}, nil},
false,
}
fmt.Printf("before src %+v\tdst %+v\n", src, dst)
copier.CopyWithOption(&dst, src, copier.Option{IgnoreEmpty: true, DeepCopy: true})
fmt.Printf("after src %+v\tdst %+v\n", src, dst)
src.M["b"] = 99
src.S[1] = 1
dst.S[0] = 2
fmt.Printf("last src %+v\tdst %+v\n\n", src, dst)
}
//before src {A:[9 10 0] S:[12 0] E:[] C: V:val M:map[A::1 b:0] AC:{Name:[ ] C:<nil>} s:true} dst {A:[1 2 3] S:[4 5 6 7] E:[9 10] C:char V:ha M:map[.:0 C::3 b:4] AC:{Name:[Y Z] C:<nil>} s:false}
//after src {A:[9 10 0] S:[12 0] E:[] C: V:val M:map[A::1 b:0] AC:{Name:[ ] C:<nil>} s:true} dst {A:[9 10 0] S:[12 0 6 7] E:[9 10] C:char V:val M:map[.:0 A::1 C::3 b:0] AC:{Name:[Y Z] C:<nil>} s:true}
//last src {A:[9 10 0] S:[12 1] E:[] C: V:val M:map[A::1 b:99] AC:{Name:[ ] C:<nil>} s:true} dst {A:[9 10 0] S:[2 0 6 7] E:[9 10] C:char V:val M:map[.:0 A::1 C::3 b:0] AC:{Name:[Y Z] C:<nil>} s:true}
//Converters
有的时候,struct1和struct2有着相同的成员变量名称,但是这个成员变量的类型不同,就比如下面,这个例子,就需要用到converts
需要注意这里的TypeConverter的定义,传入的是接口,返回的也是接口,还有这里的SrcType和DstType,传入的这个类型的任意一个值就行,不是传入字符串
go
type People1 struct {
Name string
Birthday time.Time
T time.Time
}
type People2 struct {
Name string
Birthday int64
T time.Time
}
func UnixToTime(unix any) (any, error) {
milli := time.UnixMilli(unix.(int64))
return milli, nil
}
func TimeToUnix(t any) (any, error) {
fmt.Println(t)
milli := t.(time.Time).UnixMilli()
return milli, nil
}
func main() {
var p1 = People1{Name: "fsl", Birthday: time.UnixMilli(1689423165871), T: time.UnixMilli(1689423165871)}
var p2 = People2{}
err := copier.CopyWithOption(&p2, &p1, copier.Option{Converters: []copier.TypeConverter{
{
SrcType: time.Time{},
DstType: int64(99999),
Fn: TimeToUnix,
},
}})
if err != nil {
fmt.Println(err)
return
}
fmt.Println(p1, p2)
//{fsl 2023-07-15 20:12:45.871 +0800 CST 2023-07-15 20:12:45.871 +0800 CST} {fsl 1689423165871 2023-07-15 20:12:45.871 +0800 CST}
}