mirror of
https://github.com/ralscha/godiff.git
synced 2026-10-09 09:18:26 +02:00
Structural Diff Library for Go
- Go 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .github | ||
| cmd/demo | ||
| .gitignore | ||
| basic_comparison_test.go | ||
| benchmark_test.go | ||
| collections_test.go | ||
| compare.go | ||
| configuration_test.go | ||
| edge_cases_and_memory_test.go | ||
| fuzz_test.go | ||
| go.mod | ||
| LICENSE | ||
| output.go | ||
| output_and_errors_test.go | ||
| README.md | ||
| review_fixes_test.go | ||
| Taskfile.yml | ||
| type_handlers.go | ||
| types.go | ||
| types_test.go | ||
GoDiff
Structural diff library for Go. Compares structs, slices, maps, and primitives recursively.
Requirements
Go 1.27 or newer.
Quick Start
go get github.com/ralscha/godiff
person1 := Person{Name: "Alice", Age: 30}
person2 := Person{Name: "Bob", Age: 30}
result, err := godiff.Compare(person1, person2)
if err != nil {
panic(err)
}
fmt.Println("Has Differences:", result.HasDifferences())
// Output: Has Differences: true
fmt.Println("Total differences:", result.Count())
// Output: Total differences: 1
for _, diff := range result.Diffs {
switch d := diff.(type) {
case *godiff.MapDiff:
// For map diffs
case *godiff.SliceDiff:
// For slice diffs
case *godiff.StructDiff:
fmt.Println("StructDiff - Field:", d.FieldName, "ChangeType:", d.ChangeType, "Left:", d.Left, "Right:", d.Right)
case *godiff.Diff:
// For primitive diffs
}
}
// Output: StructDiff - Field: Name ChangeType: updated Left: Alice Right: Bob
fmt.Println("JSON Output:", result.ToJSON())
// Output:
// JSON Output: [
// {
// "type": "struct",
// "path": "",
// "leftValue": "Alice",
// "rightValue": "Bob",
// "fieldName": "Name",
// "change": "UPDATED"
// }
// ]
fmt.Println(result.String())
// Output:
// Found 1 differences:
// UPDATED Name: Alice -> Bob
Configuration
Options
result, err := godiff.Compare(left, right,
godiff.WithIgnoreFields("Password", "User.Meta"),
godiff.WithIgnoreSliceOrder(),
godiff.WithCompareNumericValues(),
godiff.WithMaxDepth(10),
)
| Option | Description |
|---|---|
WithIgnoreFields(fields...) |
Skip specific fields by name or path |
WithIgnoreSliceOrder() |
Compare slices without regard to element order |
WithCompareNumericValues() |
Compare numeric values across different types |
WithMaxDepth(n) |
Limit recursion depth (0 = unlimited) |
WithCustomComparators(map) |
Custom comparison functions for specific types |
WithTypeHandlers(handlers) |
Replace all type handlers; defaults handle time.Time, interfaces, functions, and channels |
WithAdditionalTypeHandlers(handlers...) |
Add higher-priority handlers while retaining the defaults |
Options apply recursively, including inside structs, maps, ordered slices, and unordered slices. Numeric comparison is exact: large integers are not treated as equal to rounded floating-point values.
Struct Tags
type Product struct {
Name string
Tags []string `diff:"ignoreOrder"` // Compare ignoring order
Secret string `diff:"ignore"` // Skip this field
}
Demo
See the demo application for more examples:
go run ./cmd/demo
JSON
result.ToJSON() returns the formatted change array shown above using
encoding/json/v2. DiffResult implements both json.Marshaler and the more
efficient json.MarshalerTo, so it can be embedded directly in another JSON
document with json.Marshal(result).
Benchmarks
Run the benchmark suite with allocation statistics:
go test ./... -bench . -benchmem -run ^$
License
MIT