GO比較兩個(gè)對(duì)象是否相同實(shí)戰(zhàn)案例
前言
本文主要是來(lái)聊一聊關(guān)于 Golang 中的深度比較 DeepEqual
因?yàn)樽罱l(fā)現(xiàn)身邊的小伙伴寫 2 個(gè)或者多個(gè) map 比較的時(shí)候,都是自己去實(shí)現(xiàn)去比較每一個(gè)結(jié)構(gòu),每一個(gè)節(jié)點(diǎn)的 key 和 value 是不是都相等,且根據(jù)不同的數(shù)據(jù)結(jié)構(gòu),都要去實(shí)現(xiàn)一遍,沒(méi)有必要自己造輪子
我們知道,對(duì)于布爾類型,整形的,浮點(diǎn)類型,復(fù)數(shù),指針,字符串類型的值可以直接使用 ==
來(lái)進(jìn)行比較,確認(rèn)雙方是否相等
甚至對(duì)于 channel 類型,也是可以使用 ==
來(lái)進(jìn)行比較是否相等的
那么對(duì)于 golang 中的 切片 slice,數(shù)組 array,map,interface{},struct 結(jié)構(gòu)體我們?nèi)绾稳ミM(jìn)行比較呢?顯然使用 ==
是不行的,此處的 m1 和 m2 是 map[string]int
此處你是否可能會(huì)想到 C++ 還可以去重載操作符,咱們實(shí)現(xiàn)一下對(duì)應(yīng)數(shù)據(jù)類型的操作符就可以了,妥妥的
你是否還會(huì)想到 PHP 中的 ===
可以直接去比較數(shù)據(jù)的值和數(shù)據(jù)的類型,稱為全等比較運(yùn)算符
那么,看到此處,是否可以猜測(cè) golang 的做法也是類似的呢?
實(shí)際上 golang 去比較兩個(gè)對(duì)象是否相同,也是通過(guò)去比較數(shù)據(jù)的類型,數(shù)據(jù)的值,數(shù)據(jù)的長(zhǎng)度等等維度來(lái)進(jìn)行確認(rèn)的
C++ 是需要我們自己編碼實(shí)現(xiàn),PHP 是直接提供 ===
,Golang 是給我們?cè)诜瓷浒刑峁┮粋€(gè) DeepEqual 函數(shù)來(lái)進(jìn)行靈活使用
DeepEqual 案例
func DeepEqual(x, y interface{}) bool
很多朋友在不知道 golang 有提供 DeepEqual 功能的時(shí)候,比較 2 個(gè) map 可能會(huì)這樣去實(shí)現(xiàn):
func mapEqual(m1, m2 map[string]int) bool { for k, v := range m1 { vv, ok := m2[k] if !ok { return false } if v != vv { return false } } return true }
當(dāng)然也沒(méi)有啥問(wèn)題,但是如果這個(gè)時(shí)候需要我們比較兩個(gè)切片是否相等,兩個(gè)結(jié)構(gòu)體是否相等,甚至兩個(gè) interface{} 是否相等的時(shí)候,是不是都要去寫對(duì)應(yīng)的工具函數(shù)呢?
使用 DeepEqual 比較 map
兩個(gè)同一類型的 map,使用自己編寫的 mapEqual 和 使用 DeepEqual 我們得到的結(jié)果都是我們所期望的
但是對(duì)于 DeepEqual 來(lái)說(shuō),你可以傳入任何類型的數(shù)據(jù),入?yún)⑹?2 個(gè) interface{} 類型的數(shù)據(jù),響應(yīng)是 bool
對(duì)于 mapEqual 來(lái)說(shuō),你就只能傳入 map[string]int 類型的數(shù)據(jù),看到此處,自己造輪子,弊端還是很明顯的吧
自然,你也可以去將參數(shù)設(shè)計(jì)成 interface{} 類型的,然后再去進(jìn)行各種反射處理
可是明明有官方庫(kù),何必自己再弄一遍呢,我們不應(yīng)該是吸收官方的思想和精華,站在巨佬的肩膀上去做更多有意義的事情嗎
使用 DeepEqual 比較 map 和 自定義類型
可使用 DeepEqual 的時(shí)候,一定要知道他的運(yùn)作機(jī)制和原理
例如下面的案例,我們自定義一個(gè)數(shù)據(jù)類型 myType,實(shí)際上和 map[string]int 是一樣的, 可是我們?nèi)⒃?map[string]int 的 m1 和 myType 類型 m2 進(jìn)行比較的時(shí)候,他們實(shí)際上是不相等的
那么,看到這里,實(shí)際上 DeepEqual 自然是要比我們自己寫的 mapEqual 強(qiáng)太多了,他不僅關(guān)注數(shù)據(jù)的值,還會(huì)關(guān)注具體數(shù)據(jù)的類型,根據(jù)不同的數(shù)據(jù)類型,來(lái)進(jìn)行不同的數(shù)據(jù)校驗(yàn)和比較
DeepEqual 原理
DeepEqual 的代碼實(shí)現(xiàn)也非常簡(jiǎn)單,參數(shù)中傳入 interface{}, 實(shí)現(xiàn)上會(huì)去確認(rèn)具體的數(shù)據(jù)類型,是否為空,如果是一般的的數(shù)據(jù)類型,那么直接使用 ==
進(jìn)行比較即可
如果是其他的數(shù)據(jù)類型,那么就會(huì)遞歸的去調(diào)用 deepValueEqual 來(lái)一層一層的去校驗(yàn)數(shù)據(jù)和比較
為什么需要遞歸調(diào)用呢?
這個(gè)很明顯,例如對(duì)于一個(gè)切片來(lái)說(shuō),如果里面的元素是簡(jiǎn)單的字符串,或者整型數(shù)字,那么第一層使用 deepValueEqual 去識(shí)別和處理切片的類型比較,讀取到切片元素的時(shí)候就可以直接走 ==
來(lái)確認(rèn)是否相等
那么切片中也是可以是其他的任意數(shù)據(jù)結(jié)構(gòu)的,也可以是自定義的結(jié)構(gòu)體
因此在做這種比較的時(shí)候,遍歷到切片元素的時(shí)候,也要去確認(rèn)元素是什么類型的,如果是上述提到的非簡(jiǎn)單類型,那么仍然需要繼續(xù)一層一層的識(shí)別他的類型,和他的值,再進(jìn)行逐個(gè)比較
例如這樣去比較這樣結(jié)構(gòu)的切片,真的完全有必要遞歸去一層一層的確認(rèn)數(shù)據(jù)類型和數(shù)值 type Node struct{ M map[string]int In interface{} Sli []map[int][chan int] } var sli = []Node{...}
在比較的過(guò)程中,哪怕有一個(gè)環(huán)節(jié)不是我們所期望的,那么都會(huì)直接返回 false,即不相等
那么,仔細(xì)看 DeepEqual 的注釋,我們可以看到,這里有詳細(xì)的關(guān)于各種數(shù)據(jù)類型的比較和校驗(yàn)細(xì)節(jié),翻譯一下僅供大家參考,希望你有機(jī)會(huì)用到
- 數(shù)組 Array
比較相同索引處的元素是否相等
- 結(jié)構(gòu)體 struct
比較相應(yīng)字段,包括導(dǎo)出和不導(dǎo)出(此處表示字段開頭是大寫還是小寫)
- 函數(shù) Func
只有當(dāng)函數(shù)為 nil 的時(shí)候,才會(huì)是相等的,其他情況都不相等
- Interface{}
兩者都存在具體的值的時(shí)候,那么是相等的
- Map
都為空的時(shí)候是可以是相等的
都不為空的時(shí)候,會(huì)去比較他們的長(zhǎng)度,他們是否有相同的 key 且對(duì)應(yīng)相同的 value ,若都相同,則相等
- 指針 pointer
可以直接使用 == 進(jìn)行比較,和 == 效果一致,或者指針指向的值是相等的
- 切片 slice
都為 nil 的時(shí)候,是相等的
不為空的時(shí)候,會(huì)去比較他們的長(zhǎng)度,且指向的底層數(shù)組也得有相同的元素,也就是指向底層數(shù)組的地址是相同的
- 對(duì)于 other values 其他的數(shù)據(jù)類型,例如整型,布爾,字符串,通道
直接可以使用 ==
來(lái)進(jìn)行比較, DeepEqual 的源碼實(shí)現(xiàn)對(duì)于這些類型的數(shù)據(jù)也是直接使用 ==
比較的,簡(jiǎn)單粗暴
總結(jié)
本次主要聊了關(guān)于
- 非簡(jiǎn)單數(shù)據(jù)類型的比較如何去處理
- DeepEqual 的使用方式以及注意事項(xiàng)
- DeepEqual 的原理和其支持的數(shù)據(jù)類型的判定規(guī)則
到此這篇關(guān)于GO比較兩個(gè)對(duì)象是否相同的文章就介紹到這了,更多相關(guān)GO比較兩個(gè)對(duì)象相同內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang String字符串類型轉(zhuǎn)Json格式
本文主要介紹了Golang String字符串類型轉(zhuǎn)Json格式的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-05-05Go語(yǔ)言Http?Server框架實(shí)現(xiàn)一個(gè)簡(jiǎn)單的httpServer
這篇文章主要為大家介紹了Go語(yǔ)言Http?Server框架實(shí)現(xiàn)一個(gè)簡(jiǎn)單的httpServer抽象,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04go并發(fā)實(shí)現(xiàn)素?cái)?shù)篩的代碼
這篇文章主要介紹了go并發(fā)實(shí)現(xiàn)素?cái)?shù)篩的代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03利用Golang實(shí)現(xiàn)對(duì)配置文件加密
在實(shí)際的應(yīng)用中,配置文件通常包含了一些敏感的信息,如數(shù)據(jù)庫(kù)密碼、API密鑰等,為了保護(hù)這些敏感信息不被惡意獲取,我們可以對(duì)配置文件進(jìn)行加密,本文將介紹如何使用Go語(yǔ)言實(shí)現(xiàn)對(duì)配置文件的加密,需要的朋友可以參考下2023-10-10Go語(yǔ)言排序算法之插入排序與生成隨機(jī)數(shù)詳解
從這篇文章開始將帶領(lǐng)大家學(xué)習(xí)Go語(yǔ)言的經(jīng)典排序算法,比如插入排序、選擇排序、冒泡排序、希爾排序、歸并排序、堆排序和快排,二分搜索,外部排序和MapReduce等,本文將先詳細(xì)介紹插入排序,并給大家分享了go語(yǔ)言生成隨機(jī)數(shù)的方法,下面來(lái)一起看看吧。2017-11-11Go語(yǔ)言resty http包調(diào)用jenkins api實(shí)例
這篇文章主要為大家介紹了Go語(yǔ)言resty http包調(diào)用jenkins api實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06