<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
github: https://github.com/jinzhu/copier
由於 golang
沒有對複雜結構體的 clone
方法,所以,就需要有 copier
這樣的工具庫。
它看起來很簡單,但實際使用中,有些“坑”還是要注意!
本文:
入門為輔,探“坑”為主,
看完再划走,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 %+vtdst %+vn", src, dst) copier.Copy(&dst, src) fmt.Printf("after copy src %+vtdst %+vn", 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
80%的功能了。先彆著急划走,接下來還是踩坑記錄。
本文程式碼執行輸出內容是基於 github.com/jinzhu/copier@v0.3.5 和 go1.16.1 darwin/amd64 環境演示的結果。
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 %+vttdst %+vn", 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 %+vtdst %+vn", 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 得出的值四捨五入便是。
我看其他同學使用 copier
也是像上面那樣——copier.Copy($dst, src)
, 當然啦,也不排除我!它彷彿就是一把小巧精悍的小刀。一個簡單的函數呼叫,就完成了它的使命。
然而,它其實是把多功能刀,我都還沒有開啟它的—— option
。
上面的問題就是,我 Copy 後,對值的改動,影響了另一個值的 map,那麼這個時候,就需要進行深 copy。接下來引入 copier
的 option
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 %+vttdst %+vn", 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 %+vtdst %+vn", 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 %+vtdst %+vn", src, dst) copier.CopyWithOption(&dst, src, copier.Option{IgnoreEmpty: true, DeepCopy: true}) spew.Printf("after src %+vtdst %+vn", src, dst) src.M["b"] = 99 src.S[1] = 1 dst.S[0] = 2 spew.Printf("last src %+vtdst %+vnn", 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
, 也就是複製時忽略空的值。 也就說可以當作值 merge 用。
然後,又測試了一下變數獨立性。複製之後,src
, dst
兩個變數再無瓜葛,對其中一個值的任意改動都不會同步到另一個值。
但是,這個 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}
copy
了,dst
後面2,3位的值,src
沒給出,那就不管。所以就是 {12, 0, 6, 7}這塊的表現,我覺得是有爭議的,大佬們在評論區留下你預期選項,看看大家是不是都這樣想的。
實際執行結果,見上面的程式碼輸出就能找到答案。
copier
本來是一個短小精悍的工具庫,也沒想要水一篇,最近使用時,突然踩坑,就特開一篇,和大家分享一下踩坑經驗。
在使用外部庫的時候,還是建議去 github 上看看詳細說明, 或者上 pkg.go.dev 看看它暴露出來出的介面以及說明。更或者進行完整的測試,充分了解它之後,再使用。
以上就是Golang Copier入門到入坑探究的詳細內容,更多關於Golang Copier入門的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45