這篇文章專註於 6 個操作符,==,!=,<,<=,> 和 >=。我們將深入探討它們的文法和用法的細微差別。對很多人來說,這聽起來不像是迷人的事,或者他們可能已經從其他程式設計語言獲得了糟糕的經驗。然而,在 Go 中它們定義的很好並簡潔。下面討論的主題,如可比性將出現在其他場合,如 maps。為了使用上述操作符,至少有一個運算元需要[可賦值](https://studygolang.com/articles/12381)給第二個運算元:```gopackage mainimport "fmt"type T struct { name string}func main() { s := struct{ name string }{"foo"} t := T{"foo"} fmt.Println(s == t) // true}```這條規則顯著縮小了可選範圍:```govar a int = 1var b rune = '1'fmt.Println(a == b)```類似的代碼在 Javascript 或 Python 中可以運行。但在 Go 中它是非法的,並且在編譯時間會被檢測到。```src/github.com/mlowicki/lab/lab.go:8: invalid operation: a == b (mismatched types int and rune)```可賦值不是唯一要求。這是相等和順序操作符的規則……## 相等操作符運算元需要使用 `==` 或 `!=` 操作符進行比較。哪些方法,哪些值可以被比較?Go 規範定義的非常明確:* boolean 值可比較(如果倆個值都是真或假,那麼比較結果被認為 true)* 整數和浮點數比較:```govar a int = 1var b int = 2var c float32 = 3.3var d float32 = 4.4fmt.Println(a == b) // falsefmt.Println(c == d) // false```當編譯時間 `a == d` 會拋出異常( int 和 float32 類型不符)因為它不可能用 int 和 float 比較。* 複數相等,如果他們的是實數和虛數部分都相等:```govar a complex64 = 1 + 1ivar b complex64 = 1 + 2ivar c complex64 = 1 + 2ifmt.Println(a == b) // falsefmt.Println(b == c) // true```* 字串類型值可比較* 指標類型值相等,如果他們都是 nil 或都指向相同的變數:```gotype T struct { name string}func main() { t1 := T{"foo"} t2 := T{"bar"} p1 := &t1 p2 := &t1 p3 := &t2 fmt.Println(p1 == p2) // true fmt.Println(p2 == p3) // false fmt.Println(p3 == nil) // false}```> 不同的 zero-size 變數可能具有相同的記憶體位址,因此我們不假設任何指向這些變數的指標相等。```goa1 := [0]int{}a2 := [0]int{}p1 := &a1p2 := &a2fmt.Println(p1 == p2) // might be true or false. Don't rely on it!```* 通道類型值相等,如果他們確實一樣(被相同的內建 make 方法建立)或值都是 nil:```goch1 := make(chan int)ch2 := make(chan int)fmt.Println(ch1 == ch2) // false```* 介面類型是可比較。與通道和指標類型值比較一樣,如果是 nil 或 動態類型和動態值是相同的:```gotype I interface { m()}type J interface { m()}type T struct { name string}func (T) m() {}type U struct { name string}func (U) m() {}func main() { var i1, i2, i3, i4 I var j1 J i1 = T{"foo"} i2 = T{"foo"} i3 = T{"bar"} i4 = U{"foo"} fmt.Println(i1 == i2) // true fmt.Println(i1 == i3) // false fmt.Println(i1 == i4) // false fmt.Println(i1 == j1) // false}```> 比較介面類型的方法集不能相交。介面類型 I 的 i 和 非介面類型 T 的 t 可比較,如果 T 實現了 I 則 T 類型的值是可比較的。如果 I 的 動態類型和 T 是相同的,並且 i 的動態值和 t 也是相同的,那麼值是相等的:```gotype I interface { m()}type T struct{}func (T) m() {}type S struct{}func (S) m() {}func main() { t := T{} s := S{} var i I i = T{} fmt.Println(t == i) // true fmt.Println(s == i) // false}```* 結構類型可比較,所以欄位都需要比較。所有非空白欄位相等則他們等。```goa := struct { name string _ int32}{name: "foo"}b := struct { name string _ int32}{name: "foo"}fmt.Println(a == b) // true```* Go 中 數組是同質的 —— 只有同一類型(數組元素類型)的值可以被儲存其中。對於數組值比較,它們的元素類型需要可比較。如果對應的元素相同,數組就相等。就是這樣。上面列表很長但並不充滿驚奇。嘗試瞭解它在 JavaScript 是如何工作的……有三種類型不能比較 —— maps, slices 和 functions。Go 編譯器不允許這樣做,並且編譯比較 maps 的程式會引起一個錯誤 **map can only be compared to nil.**。展示的錯誤告訴我們至少可以用 maps,slices 或 functions 和 nil 比較。目前為止,我們知道介面值是可比較的,但 maps 是不可以的。如果介面值的動態類型是相同的,但是不能比較(如 maps),它會引起一個執行階段錯誤:```gotype T struct { meta map[string]string}func (T) m() {}func main() { var i1 I = T{} var i2 I = T{} fmt.Println(i1 == i2)}``````panic: runtime error: comparing uncomparable type main.Tgoroutine 1 [running]:panic(0x8f060, 0x4201a2030) /usr/local/go/src/runtime/panic.go:500 +0x1a1main.main() ...```## 順序操作符這些操作符只能應用在三種類型:整數,浮點數和字串類型。這沒有什麼特別的或 Go 特有的。值得注意的是字串是按字典順序排列的。byte-wise 一次一個位元組並沒有 Collation 演算法。```gofmt.Println("aaa" < "b") // truefmt.Println("ł" > "z") // true```## 結果任何比較操作符的結果都是無類型布爾常量(true 或 false)。因為它沒有類型,所以可以分配了給任何布爾變數:```govar t T = truet = 3.3 < 5fmt.Println(t)```這段代碼輸出 true。另一個,嘗試分配 bool 類型的值:```govar t T = truevar b bool = truet = bfmt.Println(t)```產生一個錯誤,不能使用 b (bool類型)分配給 T 類型。關於常量(有類型和無類型)更詳盡的介紹在官方[部落格](https://blog.golang.org/constants)上。
via: https://medium.com/golangspec/comparison-operators-in-go-910d9d788ec0
作者:Michał Łowicki 譯者:themoonbear 校對:polaris1119
本文由 GCTT 原創編譯,Go語言中文網 榮譽推出
本文由 GCTT 原創翻譯,Go語言中文網 首發。也想加入譯者行列,為開源做一些自己的貢獻嗎?歡迎加入 GCTT!
翻譯工作和譯文發表僅用於學習和交流目的,翻譯工作遵照 CC-BY-NC-SA 協議規定,如果我們的工作有侵犯到您的權益,請及時聯絡我們。
歡迎遵照 CC-BY-NC-SA 協議規定 轉載,敬請在本文中標註並保留原文/譯文連結和作者/譯者等資訊。
文章僅代表作者的知識和看法,如有不同觀點,請樓下排隊吐槽
149 次點擊