溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Golang怎么判斷struct/slice/map是否相等

發(fā)布時間:2022-11-29 09:56:25 來源:億速云 閱讀:105 作者:iii 欄目:開發(fā)技術

這篇文章主要介紹“Golang怎么判斷struct/slice/map是否相等”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“Golang怎么判斷struct/slice/map是否相等”文章能幫助大家解決問題。

    == 的對比方式

    == 適用的類型

    相信==判等操作,大家每天都在用。golang中對==的處理有一些細節(jié)的地方需要特別注意,==操作最重要的一個前提是:兩個操作數(shù)類型必須相同!如果類型不同,那么編譯時就會報錯。

    示例代碼:

    package main
    
    import "fmt"
    
    func main() {
        var a int32
        var b int64
        // 編譯錯誤:invalid operation a == b (mismatched types int32 and int64)
        fmt.Println(a == b)
    }

    經(jīng)常見到使用==的類型一般是:string,int等基本類型。struct有時候可以用有時候不可以。slicemap使用 ==會報錯。

    slice和map使用 ==

    因為slice和map不止是需要比較值,還需要比較len和cap,層級比較深的話還需要遞歸比較,不是簡單的==就可以比較的,所以他們各自之間是不可以直接用==比較的,slice和map只能和nil使用==。

    • 切片之間不允許比較。切片只能與nil值比較。

    • map之間不允許比較。map只能與nil值比較。

    s1 := []int64{1, 3}
    s2 := []int64{1, 2}
    if s1 == nil {} //編輯器不會提示報錯
    if s1 == s2 {} //編輯器會提示報錯

    channel使用 ==

    channel是引用類型,對比的是存儲數(shù)據(jù)的地址。channel是可以使用==的,只要類型一樣就可以。

    ch2 := make(chan int, 1)
    ch3 := ch2
    if cha2 == cha1{fmt.Println("true")} // true

    struct結(jié)構(gòu)體使用==

    結(jié)構(gòu)體的定義只是一種內(nèi)存布局的描述,只有當結(jié)構(gòu)體實例化時,才會真正地分配內(nèi)存。

    實例化就是根據(jù)結(jié)構(gòu)體定義的格式創(chuàng)建一份與格式一致的內(nèi)存區(qū)域,結(jié)構(gòu)體實例與實例間的

    內(nèi)存是完全獨立的。對結(jié)構(gòu)體進行&取地址操作時,視為對該類型進行一次 new 的實例化操作

    因此:go中的結(jié)構(gòu)體: v = Struct {}, v = &Struct{} 這個兩種寫法是等價的。

    • 簡單結(jié)構(gòu)的結(jié)構(gòu)體,里面都是值類型或者指針的話,是可以使用 ==的

    • 結(jié)構(gòu)體中含有slice或者map,都是不可以用==

    示例代碼:

    package main
    
    import (
        "fmt" 
    )
    type User struct {
        Name string
        Age  int64
    }
    type People struct {
        Name string
        Hobby []string
    }
    
    func main() {
            p1 := People{Name: "test", Hobby: []string{"唱", "跳"}}
            p2 := People{Name: "test", Hobby: []string{"唱", "跳"}}
    
            u1 := User{Name: "test", Age:18}
    		u2 := User{Name: "test", Age:18}
    
            if p1 == p2 {
                fmt.Println("p1 ==  p2") //報錯
            }
    
        	if u1 == u2 {
                fmt.Println("u1 ==  u2")
            }
        }

    reflect.DeepEqual() 和cmp.Equal()

    reflect.DeepEqual()

    reflect包提供的深度對比(遞歸)的方法,適用于go中的slice,map,struct,function的對比。

    對比規(guī)則

    • 相同類型的值是深度相等的,不同類型的值永遠不會深度相等。

    • 當數(shù)組值array的對應元素深度相等時,數(shù)組值是深度相等的。

    • 當結(jié)構(gòu)體struct值如果其對應的字段(包括導出和未導出的字段)都是深度相等的,則該值是深度相等的。

    • 當函數(shù)func值如果都是零,則是深度相等;否則就不是深度相等。

    • 當接口interface值如果持有深度相等的具體值,則深度相等。

    • 當切片slice序號相同,如果值,指針都相等,那么就是深度相等的

    • 當哈希表map相同的key,如果值,指針都相等,那么就是深度相等的。

    通過以上規(guī)則可以看到,reflect.DeepEqual是可以比較struct的,同時也可以用來比較slicemap。

    示例代碼:

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    type People struct {
        Name string
        Hobby []string
    }
    
    func main() {
            p1 := People{Name: "test", Hobby: []string{"唱", "跳"}}
            p2 := People{Name: "test", Hobby: []string{"唱", "跳"}}
            if reflect.DeepEqual(p1, p2) {
                fmt.Println("struct true")
            }
            mp1 := map[int]int{1: 1, 2: 2}
    	    mp2 := map[int]int{1: 1, 2: 2}
            if ok := reflect.DeepEqual(mp1, mp2);ok {
    			fmt.Println("mp1 == mp2!")
    	    } else {
    			fmt.Println("mp1 != mp2!")
    	    }
        }

    cmp.Equal()

    go-cmp是 Google 開源的比較庫,它提供了豐富的選項。

    對比規(guī)則

    • 在經(jīng)過路徑過濾,值過濾和類型過濾之后,會生一些忽略、轉(zhuǎn)換、比較選項,如果選項中存在忽略,則忽略比較,如果轉(zhuǎn)換器和比較器的數(shù)據(jù)大于1,則會panic(因為比較操作不明確)。如果選項中存在轉(zhuǎn)換器,則調(diào)用轉(zhuǎn)換器轉(zhuǎn)換當前值,再遞歸調(diào)用轉(zhuǎn)換器輸出類型的Equal。如果包含一個比較器。則比較使用比較器比較當前值。否則進入下一比較階段。

    • 如果比較值有一個(T) Equal(T) bool 或者 (T) Equal(I) bool,那么,即使x與y是nil,也會調(diào)用x.Equal(y)做為結(jié)果。如果不存在這樣的方法,則進入下一階段。

    • 在最后階段,Equal方法嘗試比較x與y的基本類型。使用go語言的 == 比較基本類型(bool, intX, float32,float64, complex32,complex64, string, chan)。

    • 在比較struct時,將遞歸的比較struct的字段。如果結(jié)構(gòu)體包含未導出的字段,函數(shù)會panic可以通過指定cmpopts.IgnoreUnexported來忽略未導出的字段,也可以使用cmp.AllowUnexported來指定比較未導出的字段。

    示例代碼:

    package main
    
    import (
      "fmt"
    
      "github.com/google/go-cmp/cmp"
    )
    
    type Contact struct {
      Phone string
      Email string
    }
    
    type User struct {
      Name    string
      Age     int
      Contact *Contact
    }
    
    func main() {
      u1 := User{Name: "test", Age: 18}
      u2 := User{Name: "test", Age: 18}
    
      fmt.Println("u1 == u2?", u1 == u2)  //true
      fmt.Println("u1 equals u2?", cmp.Equal(u1, u2)) //true
    
      c1 := &Contact{Phone: "123456789", Email: "dj@example.com"}
      c2 := &Contact{Phone: "123456789", Email: "dj@example.com"}
    
      u1.Contact = c1
      u2.Contact = c1
      fmt.Println("u1 == u2 with same pointer?", u1 == u2) //true
      fmt.Println("u1 equals u2 with same pointer?", cmp.Equal(u1, u2)) //true
    
      u2.Contact = c2
      fmt.Println("u1 == u2 with different pointer?", u1 == u2) //false 
      fmt.Println("u1 equals u2 with different pointer?", cmp.Equal(u1, u2)) //true
    }

    cmp和DeepEqual的區(qū)別

    • 安全:cmp.Equal()函數(shù)不會比較未導出字段(即字段名首字母小寫的字段)。遇到未導出字段,cmp.Equal()直接panic,reflect.DeepEqual()會比較未導出的字段。

    • 強大:cmp.Equal()函數(shù)提供豐富的函數(shù)參數(shù),讓我們可以實現(xiàn):忽略部分字段,比較零值,轉(zhuǎn)換某些值,允許誤差等。

    • 共同點:兩種比較類型,都會比較:對象類型,值,指針地址等。切片會按照索引比較值,map是按照key相等比較值。

    性能比較

    簡單類型的==對比速度最快

    復雜類型,自己知道結(jié)構(gòu)之后寫的自定義對比速度次之

    復雜結(jié)構(gòu)且不確定結(jié)構(gòu)的,使用cmp.Equal()或者reflect.DeepEqual()都可以,就是效率低點

    assert.Equal()底層使用的就是reflect.DeepEqual()

    關于“Golang怎么判斷struct/slice/map是否相等”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識,可以關注億速云行業(yè)資訊頻道,小編每天都會為大家更新不同的知識點。

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI