The cmp package provides two fundamental functions for comparing values: Equal for boolean equality checks and Diff for generating human-readable difference reports.
import "github.com/google/go-cmp/cmp"func Equal(x, y interface{}, opts ...Option) boolEqual reports whether x and y are equal by recursively applying comparison rules to x, y, and all their sub-values.
Parameters:
x interface{} - First value to comparey interface{} - Second value to compareopts ...Option - Optional configuration optionsReturns:
bool - True if values are equal according to comparison rulesComparison Rules (applied in order):
Options Evaluation: Applies Ignore, Transformer, and Comparer options that match the current path and values. Panics if multiple conflicting options match.
Equal Method: If values have an Equal method of form (T) Equal(T) bool or (T) Equal(I) bool, uses that result (even if x or y is nil).
Basic Kinds: Compares based on kind:
== operator==. Empty non-nil and nil maps are NOT equal.Cycle Detection: Before recursing into pointers, slices, or maps, checks if address was already visited. Cycles are equal only if both addresses were visited at same path step.
Example:
type Config struct {
Host string
Port int
}
cfg1 := Config{Host: "localhost", Port: 8080}
cfg2 := Config{Host: "localhost", Port: 8080}
cfg3 := Config{Host: "localhost", Port: 9000}
cmp.Equal(cfg1, cfg2) // returns true
cmp.Equal(cfg1, cfg3) // returns falseExample with Options:
import "github.com/google/go-cmp/cmp/cmpopts"
type Person struct {
Name string
age int // unexported
}
p1 := Person{Name: "Alice", age: 30}
p2 := Person{Name: "Alice", age: 30}
// Would panic due to unexported field
// cmp.Equal(p1, p2)
// Ignore unexported fields
cmp.Equal(p1, p2, cmpopts.IgnoreUnexported(Person{})) // returns truefunc Diff(x, y interface{}, opts ...Option) stringDiff returns a human-readable report of the differences between two values: y - x. Returns an empty string if and only if Equal returns true for the same inputs and options.
Parameters:
x interface{} - First value (baseline)y interface{} - Second value (comparison)opts ...Option - Optional configuration options (same as Equal)Returns:
string - Human-readable diff in pseudo-Go syntax, or empty string if equalOutput Format:
"-" indicate elements removed from x"+" indicate elements added from yNote: Output format is not stable and should not be parsed programmatically. Use custom Reporter for programmatic interpretation.
Example:
type User struct {
Name string
Email string
Age int
}
got := User{
Name: "Alice",
Email: "alice@example.com",
Age: 30,
}
want := User{
Name: "Alice",
Email: "alice@newdomain.com",
Age: 31,
}
diff := cmp.Diff(want, got)
if diff != "" {
fmt.Printf("User mismatch (-want +got):\n%s", diff)
}
// Output might look like:
// main.User{
// Name: "Alice",
// - Email: "alice@newdomain.com",
// + Email: "alice@example.com",
// - Age: 31,
// + Age: 30,
// }Example in Tests:
func TestProcessData(t *testing.T) {
got := ProcessData(input)
want := ExpectedResult{
Count: 5,
Items: []string{"a", "b", "c"},
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("ProcessData() mismatch (-want +got):\n%s", diff)
}
}func AllowUnexported(types ...interface{}) OptionAllowUnexported returns an Option that allows Equal to forcibly introspect unexported fields of the specified struct types.
Parameters:
types ...interface{} - Struct types to allow unexported field access (pass values of the struct types)Returns:
Option - Configuration optionNote: Prefer using Exporter or cmpopts.IgnoreUnexported for more controlled access. See Exporter documentation for proper use.
Example:
type Internal struct {
publicField string
privateField int
}
i1 := Internal{publicField: "test", privateField: 42}
i2 := Internal{publicField: "test", privateField: 42}
// Allow comparing unexported fields
cmp.Equal(i1, i2, cmp.AllowUnexported(Internal{})) // returns truefunc Exporter(f func(reflect.Type) bool) OptionExporter returns an Option that specifies whether Equal is allowed to introspect into unexported fields of certain struct types.
Parameters:
f func(reflect.Type) bool - Function that returns true if type's unexported fields can be accessedReturns:
Option - Configuration optionSafety Warning: Comparing unexported fields from external packages is not safe since internal implementation changes may cause unexpected results. For external types, prefer custom Comparers that define equality based on public API.
When to Use:
Recommended Alternatives:
Example:
import "reflect"
// Allow unexported fields only for types in our package
isOurType := func(t reflect.Type) bool {
return strings.HasPrefix(t.PkgPath(), "mycompany.com/mypackage")
}
cmp.Equal(x, y, cmp.Exporter(isOurType))Example with Comparer (preferred for external types):
import (
"reflect"
"regexp"
)
// Compare reflect.Type by pointer equality
typeComparer := cmp.Comparer(func(x, y reflect.Type) bool {
return x == y
})
// Compare regexp by string representation
regexpComparer := cmp.Comparer(func(x, y *regexp.Regexp) bool {
return x.String() == y.String()
})
cmp.Equal(x, y, typeComparer, regexpComparer)