Comparing struct, slice and map in Go: from beginner to pro
\n\nHave you ever written Go code that needed to compare two structs, two slices, or two maps, and got a compilation error: invalid operation: cannot compare? If so — you are not alone. This is one of the most popular questions on Stack Overflow (tens of thousands of views!) that stumps even experienced developers who have switched to Go from other languages.
In this article, we will finally figure out how to properly compare composite data types in Go. You will learn why == doesn't always work, when to use reflect.DeepEqual, and how to write your own efficient comparison function. Let's go!
Why doesn't simple comparison with == always work?
\n\nIn Go, the == operator only works for comparable types. These include:
- \n
- Basic types:
int,string,bool,float, etc. \n - Pointers \n
- Channels \n
- Interfaces (if the dynamic types are comparable) \n
- Structs where all fields are comparable \n
- Arrays, if the array element is comparable \n
However, slices and maps are not directly comparable using ==. Attempting to do so will result in a compilation error. Why? Because a slice is a reference type that includes a pointer to the data, length, and capacity. Two slices may be "equal" in content but have different internal structures.
package main\n\nimport "fmt"\n\nfunc main() {\n a := []int{1, 2, 3}\n b := []int{1, 2, 3}\n \n // Compilation error!\n // fmt.Println(a == b) \n \n fmt.Println("Only works with nil:")\n fmt.Println(a == nil) // false\n fmt.Println(b == nil) // false\n}\n\nThe same applies to maps. The only thing you can check with == is equality to nil.
Comparing structs in Go
\n\nComparing structs is the trickiest case. If all fields of your struct are comparable types, then == works!
type Person struct {\n Name string\n Age int\n}\n\nfunc main() {\n p1 := Person{"Alice", 30}\n p2 := Person{"Alice", 30}\n \n fmt.Println(p1 == p2) // true — works!\n}\n\nBut trouble comes when the struct contains a slice or map:
\n\ntype PersonWithHobbies struct {\n Name string\n Age int\n Hobbies []string // slice — not a comparable type\n}\n\nfunc main() {\n p1 := PersonWithHobbies{"Bob", 25, []string{"reading", "coding"}}\n p2 := PersonWithHobbies{"Bob", 25, []string{"reading", "coding"}}\n \n // Compilation error!\n // fmt.Println(p1 == p2)\n}\n\nIn this case, the Go compiler will give an error: struct containing []string cannot be compared.
Solution #1: reflect.DeepEqual — universal but slow
\n\nThe simplest way to compare any complex types is to use the reflect.DeepEqual function from the Go standard library. It recursively traverses structs, slices, maps and compares their contents.
import (\n "fmt"\n "reflect"\n)\n\nfunc main() {\n // Comparing slices\n a := []int{1, 2, 3}\n b := []int{1, 2, 3}\n fmt.Println(reflect.DeepEqual(a, b)) // true\n \n // Comparing maps\n m1 := map[string]int{"a": 1, "b": 2}\n m2 := map[string]int{"a": 1, "b": 2}\n fmt.Println(reflect.DeepEqual(m1, m2)) // true\n \n // Comparing structs with non-comparable fields\n p1 := PersonWithHobbies{"Bob", 25, []string{"reading"}}\n p2 := PersonWithHobbies{"Bob", 25, []string{"reading"}}\n fmt.Println(reflect.DeepEqual(p1, p2)) // true\n}\n\n\n