Question
In Go, how can you check whether two slices are equal when the == and != operators cannot be used?
For example, this code does not compile:
package main
import "fmt"
func main() {
s1 := []int{1, 2}
s2 := []int{1, 2}
fmt.Println(s1 == s2)
}
The compiler reports:
invalid operation: s1 == s2 (slice can only be compared to nil)
What is the correct way to compare two slices in Go?
Short Answer
By the end of this page, you will understand why slices cannot be compared directly with == in Go, how slice equality really works, and the common ways to compare slices safely. You will also learn when to use a manual loop, when reflect.DeepEqual is appropriate, and how real Go codebases usually handle slice comparison.
Concept
A slice in Go is a small descriptor that points to an underlying array, along with a length and capacity. Because of that, a slice is not a simple value like an int or bool.
Go does not allow direct comparison of two slices using == or !=, except comparing a slice to nil.
var s []int
fmt.Println(s == nil) // valid
But this is not allowed:
s1 := []int{1, 2}
s2 := []int{1, 2}
// fmt.Println(s1 == s2) // invalid
Why Go disallows slice-to-slice comparison
If Go allowed == on slices, it would need to decide what equality means:
- Are two slices equal if they point to the same underlying array?
- Or if they contain the same values?
- Should capacity matter?
- Should
niland empty slices be treated the same?
Instead of guessing, Go requires you to choose the comparison logic explicitly.
Mental Model
Think of a slice like a window looking into an array.
The slice itself is not the data. It is more like a note saying:
- where the data starts
- how many items are visible
- how much space is available
Two different windows can show the same numbers, but they are still different slice values internally.
So asking s1 == s2 is like asking whether two windows are the same object. Go does not allow that comparison.
What you usually care about is: do both windows show the same sequence of values?
That is why content-based comparison is the right mental model for slice equality.
Syntax and Examples
Manual comparison function
For beginner-friendly and efficient code, write a helper function:
package main
import "fmt"
func slicesEqual(a, b []int) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
func main() {
s1 := []int{1, 2}
s2 := []int{1, 2}
s3 := []int{1, 3}
fmt.Println(slicesEqual(s1, s2)) // true
fmt.Println(slicesEqual(s1, s3)) // false
}
How it works
len(a) != len(b)means they cannot be equalfor i := range avisits every index
Step by Step Execution
Consider this code:
package main
import "fmt"
func slicesEqual(a, b []int) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
func main() {
s1 := []int{4, 5, 6}
s2 := []int{4, 5, 6}
fmt.Println(slicesEqual(s1, s2))
}
Step-by-step
1. main creates two slices
s1contains4, 5, 6s2contains4, 5, 6
Real World Use Cases
Slice comparison appears often in Go programs.
1. Validating API results
You may call an API and compare returned IDs to expected IDs:
expected := []int{101, 102, 103}
received := []int{101, 102, 103}
A content comparison confirms the response is correct.
2. Checking processed data
After transforming input data, you may compare the output to an expected slice in tests.
Examples:
- sorted numbers
- filtered records
- mapped values
3. Comparing user permissions
A system may store allowed roles or feature flags in slices. Comparing contents helps verify whether a user has the exact expected set.
4. Detecting changes in configuration
A service might reload configuration and compare old and new lists such as:
- enabled hosts
- allowed IPs
- active modules
If the slices differ, the app may reload resources.
5. Unit testing
This is one of the most common use cases. Developers often compare expected and actual slices in tests to verify function behavior.
Real Codebase Usage
In real Go projects, developers usually avoid writing raw slice comparison logic everywhere. Instead, they use a small helper function or a well-chosen package function.
Common patterns
Guard clause for length
if len(a) != len(b) {
return false
}
This is a classic guard clause: fail early if equality is impossible.
Early return on mismatch
for i := range a {
if a[i] != b[i] {
return false
}
}
This avoids unnecessary work.
Reusable helper function
In production code, equality rules are often placed in a helper:
func equalIDs(a, b []int) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return
}
}
}
Common Mistakes
1. Trying to use == directly on slices
Broken code:
s1 := []int{1, 2}
s2 := []int{1, 2}
fmt.Println(s1 == s2) // compile error
Fix
Compare lengths and elements instead.
2. Comparing only lengths
Broken code:
func slicesEqual(a, b []int) bool {
return len(a) == len(b)
}
This is wrong because slices with the same length can still contain different values.
Example:
[]int{1, 2}
[]int{9, 9}
Both have length 2, but they are not equal.
3. Forgetting order matters
Comparisons
Slice comparison approaches
| Approach | Best for | Pros | Cons |
|---|---|---|---|
| Manual loop | Production code, simple typed slices | Fast, explicit, easy to control | More code than one function call |
reflect.DeepEqual | Tests, quick checks, generic comparisons | Convenient, works for many types | Uses reflection, less explicit |
| Custom business-rule comparison | Special equality rules | Flexible | You must define and maintain the rules |
nil vs empty slice
| Value | Example | Length | Usually means |
|---|
Cheat Sheet
Quick rules
- Slices cannot be compared with
==or!= - A slice can only be compared to
nil - To check equality by contents:
- compare lengths
- compare each element in order
reflect.DeepEqualcan compare slices, but manual comparison is often clearer
Basic pattern
func slicesEqual(a, b []int) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
nil comparison
var s []int
fmt.Println(s == nil) // true
Reflection option
FAQ
Why can't slices be compared with == in Go?
Because slices are descriptor types, not simple comparable values. Go only allows slice comparison with nil.
What is the easiest way to compare two slices in Go?
For simple typed slices, write a helper that compares length and then each element.
Can I use reflect.DeepEqual to compare slices?
Yes. It works for many cases and is especially common in tests, but explicit comparison is often clearer in production code.
Are two empty slices equal in Go?
If both have zero length and your comparison checks only contents, they may be treated as equal. But nil and empty slices are not always identical concepts.
Does slice order matter when comparing equality?
Yes. []int{1, 2} and []int{2, 1} are different if you compare by index.
Can arrays be compared with == in Go?
Yes, arrays can be compared directly if their element type is comparable.
What should I use in tests to compare slices?
A helper function or reflect.DeepEqual are both common choices, depending on how explicit you want the test to be.
Mini Project
Description
Build a small Go program that compares two slices of integers entered in code and reports whether they are equal. This project reinforces the idea that slices must be compared by contents, not with ==.
Goal
Create a reusable slice comparison function and use it to check multiple pairs of slices.
Requirements
- Write a function that accepts two
[]intvalues and returns abool - Return
falseif the slice lengths are different - Compare elements in order and stop early on the first mismatch
- Print results for at least three example slice pairs
Keep learning
Related questions
Check if a Value Exists in a Slice in Go
Learn how to check whether a value exists in a slice in Go, and why Go has no Python-style `in` operator for arrays or slices.
Concatenating Slices in Go with append
Learn how to concatenate two slices in Go using append and the ... operator, with examples, pitfalls, and practical usage.
Convert String to Integer in Go: Idiomatic Parsing with strconv.Atoi
Learn the idiomatic way to convert a string to an int in Go using strconv.Atoi, with examples, errors, and common mistakes.