How to Compare Struct, Slice or Map in GO? [SOLVED]


GO

Author: Tuan Nguyen
Reviewer: Deepak Prasad

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

 

Tuan Nguyen

Tuan Nguyen

He is proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise spanning these technologies, he develops robust solutions and implements efficient data processing and management strategies across various projects and platforms. You can connect with him on his LinkedIn profile.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment