微信搜索【 腦子進煎魚了】關注這一隻爆肝煎魚。本文 GitHub github.com/eddycjy/blog 已收錄,有個人系列文章、資料和開源 Go 圖書。
你們好,我是煎魚。git
最近金三銀四,是面試的季節。在個人 Go 讀者交流羣裏出現了許多小夥伴在討論本身面試過程當中所遇到的一些 Go 面試題。github
今天的男主角,是 Go 工程師的必修技能,也是極容易踩坑的地方,就是 「Go 面試題:Go 結構體(struct)是否能夠比較?」golang
若是能夠比較,是爲何?若是不能夠比較,又是爲何?面試
請在此處默唸本身心目中的答案,再往和煎魚一塊兒研討一波 Go 的技術哲學。算法
在 Go 語言中有個基本類型,開發者們稱之爲結構體(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 語言語法基礎。spa
接下來正式開始研討 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 語言的坑,真實狀況是結構體是可比較,也不可比較的,不要誤入歧途了,這是一個很是 "有趣" 的現象。
接下來繼續改造上面的例子,咱們在本來的結構體中增長了指針類型的引用。
第二個例子以下:
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("腦子沒進煎魚") }
這段程序輸出結果是什麼呢,咱們猜想一下,變量依然是同一結構體的兩個實例,值的賦值方式和內容都是同樣的,是否應當輸出 「腦子進煎魚了」?
答案是:腦子沒進煎魚。
咱們繼續不信邪,試試另外的基本類型,看看結果是否是仍是相等的。
第三個例子以下:
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 也提示錯誤,一隻煎魚都沒能輸出出來。
那不一樣結構體,相同的值內容呢,可否進行比較?
第四個例子:
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)
那是否是就徹底無法比較了呢?並不,咱們能夠藉助強制轉換來實現:
if v1 == Value1(v2) { fmt.Println("腦子進煎魚了") return }
這樣程序就會正常運行,且輸出 「腦子進煎魚了」。固然,如果不可比較類型,依然是不行的。
爲何 Go 結構體有的比較就是正常,有的就不行,甚至還直接報錯了。難道是有什麼 「潛規則」 嗎?
在 Go 語言中,Go 結構體有時候並不能直接比較,當其基本類型包含:slice、map、function 時,是不能比較的。若強行比較,就會致使出現例子中的直接報錯的狀況。
而指針引用,其雖然都是 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
經常使用於斷定兩個值是否深度一致,其規則以下:
更具體的你們可到 golang.org/pkg/reflect/#DeepEqual
進行詳細查看:
該方法對 Go 語言中的各類類型都進行了兼容處理和判別,因爲這不是本文的重點,所以就不進一步展開了。
在本文中,咱們針對 Go 語言的結構體(struct)是否可以比較進行了具體例子的展開和說明。
其本質上仍是對 Go 語言基本數據類型的理解問題,算是變形到結構體中的具體進一步拓展。
不知道你有沒有在 Go 結構體吃過什麼虧呢,歡迎在下方評論區留言和咱們一塊兒交流和討論。
如有任何疑問歡迎評論區反饋和交流,最好的關係是互相成就,各位的點贊就是煎魚創做的最大動力,感謝支持。
文章持續更新,能夠微信搜【腦子進煎魚了】閱讀,回覆【 000】有我準備的一線大廠面試算法題解和資料;本文 GitHub github.com/eddycjy/blog 已收錄,歡迎 Star 催更。