In Golang, it is very simple to compare the basic data types: int64, float64, string, and boolean: we just need to use the ==
or !=
operator. But for the complex data type such as structs, slices, or maps, how can we know if two variables are equal? In today's article, I will show you several methods to determine if two structs, slices, or maps are equal or not. We can use some built-in function or write our code to perform this operation.
Method 1: Using the DeepEqual() function to compare structs, slices, and maps
func DeepEqual(x, y any) bool
: DeepEqual reports whether x and y are “deeply equal,” defined as follows. Two values of the identical type are deeply equal if one of the following cases applies. Values of distinct types are never deeply equal:
1. Slice values are deeply equal when all of the following are true: they are both nil or both non-nil, they have the same length, and either they point to the same initial entry of the same underlying array (that is, &x[0] == &y[0]
) or their corresponding elements (up to length) are deeply equal. Note that a non-nil empty slice and a nil slice (for example, []byte{} and []byte(nil)
) are not deeply equal.
2. Struct values are deeply equal if their corresponding fields, both exported and unexported, are deeply equal.
3. Map values are deeply equal when all of the following are true: they are both nil or both non-nil, they have the same length, and either they are the same map object or their corresponding keys (matched using Go equality) map to deeply equal values.
Compare two structs
The example below shows how to use the DeepEqual()
function to compare two structs:
package main
import (
"fmt"
"reflect"
)
type person struct {
name string
age int
}
func main() {
person1 := person{"Bob", 20}
person2 := person{"Bob", 20}
person3 := person{"Anna", 20}
fmt.Println("person1 equal person2?:", reflect.DeepEqual(person1, person2))
fmt.Println("person1 equal person3?:", reflect.DeepEqual(person1, person3))
}
Output:
person1 equal person2?: true
person1 equal person3?: false
Compare two slices
The example below shows how to use the DeepEqual()
function to compare two slices:
package main
import (
"fmt"
"reflect"
)
func main() {
slice1 := []int{1, 2, 3}
slice2 := []int{1, 2, 3}
slice3 := []int{1, 2}
fmt.Println("slice1 equal slice2?:", reflect.DeepEqual(slice1, slice2))
fmt.Println("slice1 equal slice3?:", reflect.DeepEqual(slice1, slice3))
}
Output:
slice1 equal slice2?: true
slice1 equal slice3?: false
Compare two maps
The example below shows how to use the DeepEqual()
function to compare two maps:
package main
import (
"fmt"
"reflect"
)
func main() {
map1 := map[string]string{
"Anna": "anna@gmail.com",
"Bob": "bob@gmail.com",
}
map2 := map[string]string{
"Anna": "anna@gmail.com",
"Bob": "bob@gmail.com",
}
map3 := map[string]string{
"Anna": "anna@gmail.com",
"Daniel": "daniel@gmail.com",
}
fmt.Println("map1 equal map2?:", reflect.DeepEqual(map1, map2))
fmt.Println("map1 equal map3?:", reflect.DeepEqual(map1, map3))
}
Output:
map1 equal map2?: true
map1 equal map3?: false
Method 2: Write our own function to compare maps, structs, and slices
Depending on what kind of business logic we want, we can define our functions to determine if two structs, maps, and slices are equal or not. The following code shows the basic logic to compare 2 maps and slices:
package main
import (
"fmt"
)
func main() {
map1 := map[string]string{
"Anna": "anna@gmail.com",
"Bob": "bob@gmail.com",
}
map2 := map[string]string{
"Anna": "anna@gmail.com",
"Bob": "bob@gmail.com",
}
slice1 := []int{1, 2, 3}
slice2 := []int{1, 2, 3}
t1 := T{slice1, map1}
t2 := T{slice2, map2}
fmt.Println("t1 equal t2?:", compare(t1, t2))
}
type T struct {
Z []int
M map[string]string
}
func compare(a, b T) bool {
if &a == &b {
return true
}
if len(a.Z) != len(b.Z) || len(a.M) != len(b.M) {
return false
}
//compare 2 slice
for i, v := range a.Z {
if b.Z[i] != v {
return false
}
}
//compare 2 maps
for k, v := range a.M {
if b.M[k] != v {
return false
}
}
return true
}
Output:
t1 equal t2?: true
Method 3: Use some other functions to compare maps, slices, and structs
Use the cmp.Equal()
to compare two structs
func Equal(x, y interface{}, opts ...Option) bool
: Equal reports whether x and y are equal by recursively applying the following rules in the given order to x and y and all of their sub-values.
In this example, we will try to compare 2 structs by using the cmp.Equal()
and the cmpopts.IgnoreFields
option which skips comparing some fields in the struct:
package main
import (
"fmt"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
)
type Person struct {
Name string
Age int
}
func main() {
person1 := Person{"Bob", 20}
person2 := Person{"Bob", 20}
person3 := Person{"Bob", 40}
fmt.Println("person1 equal person2?:", cmp.Equal(person1, person2))
fmt.Println("person1 equal person3?:", cmp.Equal(person1, person3))
fmt.Println("person1 equal person3 skip age?:", cmp.Equal(person1, person3, cmpopts.IgnoreFields(Person{}, "Age")))
}
Output:
person1 equal person2?: true
person1 equal person3?: false
person1 equal person3 skip age?: true
Noted that be careful when using this method because it is intended to only be used in tests, as performance is not a goal and it may panic if it cannot compare the values. Its propensity towards panicking means that it's unsuitable for production environments where a spurious panic may be fatal.
Use == operate to compare one-level structs
If you want to compare simple one-level structs, the best and simple method is using the == operator:
package main
import (
"fmt"
)
type Person struct {
Name string
Age int
}
func main() {
person1 := Person{"Bob", 20}
person2 := Person{"Bob", 20}
person3 := Person{"Bob", 40}
fmt.Println("person1 equal person2?:", person1 == person2)
fmt.Println("person1 equal person3?:", person1 == person3)
}
Output:
person1 equal person2?: true
person1 equal person3?: false
Using the maps.Equal() to compare maps; slices.Equal() to compare slices
Go generics have introduced a new function to compare two maps and two slices. First, you need to get some additional packages:
go get golang.org/x/exp/maps go get golang.org/x/exp/slices
Here is an example of using the Equal()
functions to compare slices and maps:
package main
import (
"fmt"
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
)
func main() {
map1 := map[string]string{
"Anna": "anna@gmail.com",
"Bob": "bob@gmail.com",
}
map2 := map[string]string{
"Anna": "anna@gmail.com",
"Bob": "bob2@gmail.com",
}
slice1 := []int{1, 2, 3}
slice2 := []int{1, 2, 3}
fmt.Println("map1 equal map2?:", maps.Equal(map1, map2))
fmt.Println("map1 equal map2?:", slices.Equal(slice1, slice2))
}
Output:
map1 equal map2?: false
map1 equal map2?: true
Summary
In Golang, the DeepEqual
function is used to compare struct, slice, and map equality. It is used to determine whether or not two items are "deeply equal". Besides this function, we also can use some other functions such as cmp.Equal()
, maps.Equal
and slices.Equal()
. Last but not least, we can also build your own version of the compare function as shown above.
References
http://golang.org/pkg/reflect/#DeepEqual
https://pkg.go.dev/github.com/google/go-cmp/cmp#Equal