Generating Equal methods for Go structs with goderive

Sometimes you need to check the equality of two structs in Go, and depending on how complicated they are, you probably want to avoid hand-writing the Equal method if possible, and you want to avoid reflect.DeepEqual for performance reasons, at least in your production code.
If I were writing Java, I'd ask IntelliJ to generate an equals method for me, but wanted to find out if Go had a tool for this, because there usually is one. I asked around in the Go communities I'm part of, and my colleague Michal suggested looking at goderive, which worked out very nicely for what I needed.
Although goderive supports many methods being generated, I only needed an Equal method.
Let's say that we have a slightly complex struct setup which results in this set of types:
type ComplexStruct struct {
Int int
MyStruct MyStruct
Anon Anon
}
type Anon struct {
Nested Nested
}
type Nested struct {
MyStruct MyStruct
}
type MyStruct struct {
Int64 int64
StringPtr *string
}
To create our own Equal method is OK for us to do, but we can instead use goderive to do the heavy lifting, by creating:
func (this *ComplexStruct) Equal(that *ComplexStruct) bool {
return deriveEqualComplexStruct(this, that)
}
Note that there needs to be pointer receivers for goderive to generate the right equality method.
This will fail to compile - but that's OK, running goderive will then auto-generate the file derived.gen.go which contains the implementation we need:
// deriveEqualComplexStruct returns whether this and that are equal.
func deriveEqualComplexStruct(this, that *ComplexStruct) bool {
return (this == nil && that == nil) ||
this != nil && that != nil &&
this.Int == that.Int &&
deriveEqual(&this.MyStruct, &that.MyStruct) &&
deriveEqual_(&this.Anon, &that.Anon)
}
// deriveEqual returns whether this and that are equal.
func deriveEqual(this, that *MyStruct) bool {
return (this == nil && that == nil) ||
this != nil && that != nil &&
this.Int64 == that.Int64 &&
((this.StringPtr == nil && that.StringPtr == nil) || (this.StringPtr != nil && that.StringPtr != nil && *(this.StringPtr) == *(that.StringPtr)))
}
// deriveEqual_ returns whether this and that are equal.
func deriveEqual_(this, that *Anon) bool {
return (this == nil && that == nil) ||
this != nil && that != nil &&
deriveEqual_1(&this.Nested, &that.Nested)
}
// deriveEqual_1 returns whether this and that are equal.
func deriveEqual_1(this, that *Nested) bool {
return (this == nil && that == nil) ||
this != nil && that != nil &&
deriveEqual(&this.MyStruct, &that.MyStruct)
}
This then generates a set of methods which check the equality for all the types involved - awesome π
A sample project for this can be found on GitLab.com.