github: https://github.com/jinzhu/copier
golangclonecopier
它看起来很简单,但实际使用中,有些“坑”还是要注意!
本文:
入门为辅,探“坑”为主,
看完再划走,CS我没有。
安装
go get github.com/jinzhu/copier
快速入门
copier
package main
import (
"fmt"
"github.com/jinzhu/copier"
)
type SC struct {
C uint8
}
type M1 struct {
A int
W string
S *SC
}
func main() {
var src = M1{12, "Hello", &SC{32}}
var dst = M1{}
fmt.Printf("before copy src %+v\tdst %+v\n", src, dst)
copier.Copy(&dst, src)
fmt.Printf("after copy src %+v\tdst %+v\n", src, dst)
}
输出:
before copy src {A:12 W:Hello S:0xc00017f550} dst {A:0 W: S:<nil>}
after copy src {A:12 W:Hello S:0xc00017f550} dst {A:12 W:Hello S:0xc00017f618}
copier
本文代码运行输出内容是基于 github.com/jinzhu/copier@v0.3.5 和 go1.16.1 darwin/amd64 环境演示的结果。
http://itjsz.com
入坑
package main
import (
"fmt"
"github.com/davecgh/go-spew/spew"
"github.com/jinzhu/copier"
)
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{}
spew.Printf("before src %+v\t\tdst %+v\n", src, dst1)
copier.Copy(&dst1, src)
dst1.M["F"] = 5
dst1.M["g"] = 6
dst1.A[0] = 7
dst1.C.C = 27
spew.Printf("after src %+v\tdst %+v\n", src, dst1)
}
以上代码运行后会输出:
before src {M:map[C::3 d:4] A:[9 8] C:<*>(0xc00012a1e8){C:32}} dst {M:<nil> A:<nil> C:<nil>}
befre 那一行代码如上⬆️ , after 那一行会输出什么呢?
1. after src {M:map[C::3 d:4] A:[9 8] C:<*>(0xc00012a1e8){C:27}} dst {M:map[C::3 d:4 F:5 g:6] A:[7 8] C:<*>(0xc00012a348){C:27}}
2. after src {M:map[C::3 d:4] A:[9 8] C:<*>(0xc00012a1e8){C:32}} dst {M:map[C::3 d:4 F:5 g:6] A:[7 8] C:<*>(0xc00012a348){C:27}}
3. after src {M:map[C::3 d:4] A:[7 8] C:<*>(0xc00012a1e8){C:32}} dst {M:map[C::3 d:4 F:5 g:6] A:[7 8] C:<*>(0xc00012a348){C:27}}
4. after src {M:map[C::3 d:4 F:5 g:6] A:[7 8] C:<*>(0xc00012a1e8){C:32}} dst {M:map[C::3 d:4 F:5 g:6] A:[7 8] C:<*>(0xc00012a348){C:27}}
5. after src {M:map[C::3 d:4 F:5 g:6] A:[7 8] C:<*>(0xc00012a1e8){C:27}} dst {M:map[C::3 d:4 F:5 g:6] A:[7 8] C:<*>(0xc00012a348){C:27}}
答案是: var a = int(759 / 6 / 31.5)
为了避免不小心看了答案,请计算 759 / 6 / 31.5 得出的值四舍五入便是。
再探坑
出坑
copiercopier.Copy($dst, src)
option
copieroption
package main
import (
"fmt"
"github.com/davecgh/go-spew/spew"
"github.com/jinzhu/copier"
)
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{}
spew.Printf("before src %+v\t\tdst %+v\n", src, dst1)
copier.CopyWithOption(&dst1, src, copier.Option{DeepCopy: true}) // 这里!
dst1.M["F"] = 5
dst1.M["g"] = 6
dst1.A[0] = 7
dst1.C.C = 27
spew.Printf("after src %+v\tdst %+v\n", src, dst1)
}
好的,这样copy之后,对新变量的改动,不会传递会原变量改动了。
再盘一盘坑
package main
import (
"fmt"
"github.com/davecgh/go-spew/spew"
"github.com/jinzhu/copier"
)
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,
}
spew.Printf("before src %+v\tdst %+v\n", src, dst)
copier.CopyWithOption(&dst, src, copier.Option{IgnoreEmpty: true, DeepCopy: true})
spew.Printf("after src %+v\tdst %+v\n", src, dst)
src.M["b"] = 99
src.S[1] = 1
dst.S[0] = 2
spew.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[C::3 b:4 .:0] 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[A::1 C::3 b:0 .: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[C::3 b:0 .:0 A::1] AC:{Name:[Y Z] C:<nil>} s:true}
IgnoreEmpty: true
srcdst
merge
src.S = []int32{12, 0}
dst.S = []int32{4, 5, 6, 7}
## 调用 copy 后, 你预期的结果是什么?[6/7]
6. dst.S = []int32{12, 0}
7. dst.S = []int32{12, 0, 6, 7}
copydstsrc
这块的表现,我觉得是有争议的,大佬们在评论区留下你预期选项,看看大家是不是都这样想的。
实际运行结果,见上面的代码输出就能找到答案。
结语
copier
在使用外部库的时候,还是建议去 github 上看看详细说明, 或者上 pkg.go.dev 看看它暴露出来出的接口以及说明。更或者进行完整的测试,充分了解它之后,再使用。
PS: 最近项目中使用这个库,发现问题后,改疯了~