1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        手撕 Go 面試官:Go 結構體是否可以比較,為什么?

        共 5904字,需瀏覽 12分鐘

         ·

        2021-06-22 10:01

        今天的男主角,是 Go 工程師的必修技能,也是極容易踩坑的地方,就是 “Go 面試題:Go 結構體(struct)是否可以比較?

        如果可以比較,是為什么?如果不可以比較,又是為什么?

        請在此處默念自己心目中的答案,再往和煎魚一起研討一波 Go 的技術哲學。

        結構體是什么

        在 Go 語言中有個基本類型,開發(fā)者們稱之為結構體(struct)。是 Go 語言中非常常用的,基本定義:

        type struct_variable_type struct {
            member definition
            member definition
            ...
            member definition
        }

        簡單示例:

        package main

        import "fmt"

        type Vertex struct {
            Name1 string
            Name2 string
        }

        func main() {
            v := Vertex{"腦子進了""煎魚"}
            v.Name2 = "蒸魚"
            fmt.Println(v.Name2)
        }

        輸出結果:

        蒸魚

        這部分屬于基礎知識,因此不再過多解釋。如果看不懂,建議重學 Go 語言語法基礎。

        比較兩下

        例子一

        接下來正式開始研討 Go 結構體比較的問題,第一個例子如下:

        type Value struct {
            Name   string
            Gender string
        }

        func main() {
            v1 := Value{Name: "煎魚", Gender: "男"}
            v2 := Value{Name: "煎魚", Gender: "男"}
            if v1 == v2 {
                fmt.Println("腦子進煎魚了")
                return
            }

            fmt.Println("腦子沒進煎魚")
        }

        我們聲明了兩個變量,分別是 v1 和 v2。其都是 Value 結構體的實例化,是同一個結構體的兩個實例。

        他們的比較結果是什么呢,是輸出 ”腦子進煎魚了“,還是 ”腦子沒進煎魚“?

        輸出結果:

        腦子進煎魚了

        最終輸出結果是 ”腦子進煎魚了“,初步的結論是可以結構體間比較的。皆大歡喜,那這篇文章是不是就要結束了?

        當然不是...很多人都會踩到這個 Go 語言的坑,真實情況是結構體是可比較,也不可比較的,不要誤入歧途了,這是一個非常 "有趣" 的現(xiàn)象。

        例子二

        接下來繼續(xù)改造上面的例子,我們在原本的結構體中增加了指針類型的引用。

        第二個例子如下:

        type Value struct {
            Name   string
            Gender *string
        }

        func main() {
            v1 := Value{Name: "煎魚", Gender: new(string)}
            v2 := Value{Name: "煎魚", Gender: new(string)}
            if v1 == v2 {
                fmt.Println("腦子進煎魚了")
                return
            }

            fmt.Println("腦子沒進煎魚")
        }

        這段程序輸出結果是什么呢,我們猜測一下,變量依然是同一結構體的兩個實例,值的賦值方式和內(nèi)容都是一樣的,是否應當輸出 “腦子進煎魚了”?

        答案是:腦子沒進煎魚。

        例子三

        我們繼續(xù)不信邪,試試另外的基本類型,看看結果是不是還是相等的。

        第三個例子如下:

        type Value struct {
            Name   string
            GoodAt []string
        }

        func main() {
            v1 := Value{Name: "煎魚", GoodAt: []string{"炸""煎""蒸"}}
            v2 := Value{Name: "煎魚", GoodAt: []string{"炸""煎""蒸"}}
            if v1 == v2 {
                fmt.Println("腦子進煎魚了")
                return
            }

            fmt.Println("腦子沒進煎魚")
        }

        這段程序輸出結果是什么呢?

        答案是:

        # command-line-arguments
        ./main.go:15:8: invalid operation: v1 == v2 (struct containing []string cannot be compared)

        程序運行就直接報錯,IDE 也提示錯誤,一只煎魚都沒能輸出出來。

        例子四

        那不同結構體,相同的值內(nèi)容呢,能否進行比較?

        第四個例子:

        type Value1 struct {
            Name string
        }

        type Value2 struct {
            Name string
        }

        func main() {
            v1 := Value1{Name: "煎魚"}
            v2 := Value2{Name: "煎魚"}
            if v1 == v2 {
                fmt.Println("腦子進煎魚了")
                return
            }

            fmt.Println("腦子沒進煎魚")
        }

        顯然,會直接報錯:

        # command-line-arguments
        ./main.go:18:8: invalid operation: v1 == v2 (mismatched types Value1 and Value2)

        那是不是就完全沒法比較了呢?并不,我們可以借助強制轉換來實現(xiàn):

         if v1 == Value1(v2) {
          fmt.Println("腦子進煎魚了")
          return
         }

        這樣程序就會正常運行,且輸出 “腦子進煎魚了”。當然,若是不可比較類型,依然是不行的。

        為什么

        為什么 Go 結構體有的比較就是正常,有的就不行,甚至還直接報錯了。難道是有什么 “潛規(guī)則” 嗎?

        在 Go 語言中,Go 結構體有時候并不能直接比較,當其基本類型包含:slice、map、function 時,是不能比較的。若強行比較,就會導致出現(xiàn)例子中的直接報錯的情況。

        而指針引用,其雖然都是 new(string),從表象來看是一個東西,但其具體返回的地址是不一樣的。

        因此若要比較,則需改為:

        func main() {
            gender := new(string)
            v1 := Value{Name: "煎魚", Gender: gender}
            v2 := Value{Name: "煎魚", Gender: gender}
            ...
        }

        這樣就可以保證兩者的比較。如果我們被迫無奈,被要求一定要用結構體比較怎么辦?

        這時候可以使用反射方法 reflect.DeepEqual,如下:

        func main() {
            v1 := Value{Name: "煎魚", GoodAt: []string{"炸""煎""蒸"}}
            v2 := Value{Name: "煎魚", GoodAt: []string{"炸""煎""蒸"}}
            if reflect.DeepEqual(v1, v2) {
                fmt.Println("腦子進煎魚了")
                return
            }

            fmt.Println("腦子沒進煎魚")
        }

        這樣子就能夠正確的比較,輸出結果為 “腦子進煎魚了”。

        例子中所用到的反射比較方法 reflect.DeepEqual 常用于判定兩個值是否深度一致,其規(guī)則如下:

        • 相同類型的值是深度相等的,不同類型的值永遠不會深度相等。
        • 當數(shù)組值(array)的對應元素深度相等時,數(shù)組值是深度相等的。
        • 當結構體(struct)值如果其對應的字段(包括導出和未導出的字段)都是深度相等的,則該值是深度相等的。
        • 當函數(shù)(func)值如果都是零,則是深度相等;否則就不是深度相等。
        • 當接口(interface)值如果持有深度相等的具體值,則深度相等。
        • ...

        更具體的大家可到 golang.org/pkg/reflect/#DeepEqual 進行詳細查看:

        reflect.DeepEqual 完整說明

        該方法對 Go 語言中的各種類型都進行了兼容處理和判別,由于這不是本文的重點,因此就不進一步展開了。

        總結

        在本文中,我們針對 Go 語言的結構體(struct)是否能夠比較進行了具體例子的展開和說明。

        其本質(zhì)上還是對 Go 語言基本數(shù)據(jù)類型的理解問題,算是變形到結構體中的具體進一步拓展。

        不知道你有沒有在 Go 結構體吃過什么虧呢,歡迎在下方評論區(qū)留言和我們一起交流和討論




        關注煎魚公眾號,吸取精華:

        ?? 點擊關注煎魚,在知識的海洋里遨游

        瀏覽 33
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产精品 色哟哟 | 天天射天天爽 | 看全色黄大色黄大片大学生 | 日韩精品成人免费观看视频 | 色爱激情网 | 国产精品羞羞答答在线观看 | 麻豆精品秘 国产传媒电影 | 公交车地铁高h荡肉呻吟 | 操碰在线观看 | 美女逼被靠肿网站 |