Detail comparison operators in THE Go language

  • 2020-06-15 09:17:07
  • OfStack

This article focuses on 6 operators, ==,! =, < . < =, > and > =. We'll delve into the nuances of their syntax and usage. For many people, this may not sound appealing, or they may have had bad experiences with other programming languages. However, in Go they are well defined and succinct. Topics such as comparability will be discussed below in other contexts such as maps. In order to use the above operator, at least one operand needs to be assignable to the second:


package main
import "fmt"
type T struct {
  name string
}
func main() {
  s := struct{ name string }{"foo"}
  t := T{"foo"}
  fmt.Println(s == t) // true
}

This rule significantly Narrows the options:


var a int = 1
var b rune = '1'
fmt.Println(a == b)

Similar code can be run in Javascript or Python. But in Go it is illegal and is detected when compiled.


src/github.com/mlowicki/lab/lab.go:8: invalid operation: a == b (mismatched types int and rune)

Assignable is not the only 1 requirement. This is the rule for equality and sequence operators...

Equality operator

Operands need to use == or! = operator to compare. Which methods and which values can be compared? The Go specification is very clearly defined:

boolean values are comparable (if both values are true or false, the comparison is considered true)
Integer versus floating-point Numbers:


var a int = 1
var b int = 2
var c float32 = 3.3
var d float32 = 4.4
fmt.Println(a == b) // false
fmt.Println(c == d) // false

a == d throws an exception when compiled (int and float32 types do not match) because it cannot be compared with int.

The complex Numbers are equal if their real and imaginary parts are equal:


var a complex64 = 1 + 1i
var b complex64 = 1 + 2i
var c complex64 = 1 + 2i
fmt.Println(a == b) // false
fmt.Println(b == c) // true

String type values are comparable

Pointer type values are equal if they are both nil or all point to the same variable:


type 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
}

Different ES53en-ES54en variables may have the same memory address, so we do not assume that any Pointers to these variables are equal.


a1 := [0]int{}
a2 := [0]int{}
p1 := &a1
p2 := &a2
fmt.Println(p1 == p2) // might be true or false. Don't rely on it!

Channel type values are equal if they are exactly 1 like (created by the same built-in make method) or both nil:


ch1 := make(chan int)
ch2 := make(chan int)
fmt.Println(ch1 == ch2) // false

The interface type is comparable. Compare 1 with channel and pointer type values, if nil or dynamic type and dynamic value are the same:


type 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
}

A set of methods that compare interface types cannot intersect.

The i of the interface type I is comparable to the t of the non-interface type T, and the value of the T type is comparable if T implements I. If the dynamic type of I is the same as that of T and the dynamic value of i is the same as that of t, then the value is equal:


type 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
}
 Structure types are comparable, so fields need to be compared. If all non-blank fields are equal, they etc. 
a := struct {
  name string
  _ int32
}{name: "foo"}
b := struct {
  name string
  _ int32
}{name: "foo"}
fmt.Println(a == b) // true

Arrays in Go are homogeneous -- only values of the same type (array element type) can be stored there. For array value comparisons, their element types need to be comparable. If the corresponding elements are the same, the array is equal.

That's it. The list is long but not full of surprises. Try to understand how it works at JavaScript...

There are three types that cannot be compared - maps, slices and functions. The Go compiler does not allow this and compiling a program that compares maps causes an error map can only compared to nil. The errors shown tell us that we can at least compare maps, slices or functions to nil.

So far, we know that interface values are comparable, but maps is not. If the dynamic type of the interface value is the same, but cannot be compared (such as maps), it causes a runtime error:


var a int = 1
var b rune = '1'
fmt.Println(a == b)
0

Sequential operator

These operators can only be applied to three types: integer, floating point, and string. There is nothing special or Go specific about this. It is worth noting that the strings are arranged in dictionary order. byte-wise 1 byte at a time does not have the Collation algorithm.


var a int = 1
var b rune = '1'
fmt.Println(a == b)
1

The results of

The result of any comparison operator is an untyped Boolean constant (true or false). Because it has no type, it can be assigned to any Boolean variable:


var a int = 1
var b rune = '1'
fmt.Println(a == b)
2

This code outputs true. Another, trying to assign a value of type bool:


var t T = true
var b bool = true
t = b
fmt.Println(t)

An error occurred that could not be assigned to the T type using b (bool type).

conclusion


Related articles: