I have a struct in Go, which represents a state. I now want to be able to compare two states (current & desired), whereby each field is compared with the other. I define two states as "equal" if all fields are "equal". However, in some cases, field equality is rather loose, which I want to be customely define.
Let's say one of the state fields in "RestartedAfter". If current-state RestartedAfter is greater than desired-state RestartedAfter, then I consider the two "equal".
In the example I only use a single field, but since I want to iterate over all fields of the struct (in the next step),
I thought about using type parameters to define an AssertEqual()
interface, which all fields in the state-struct
should implement.
type StateField[T any] interface {
AssertEqual(T) error
}
type RestartedAfter int
func (current RestartedAfter) AssertEqual(desired RestartedAfter) error {
if current >= desired {
return nil
}
return errors.New("current RestartedAfter happened before desired RestartedAfter")
}
func compareTwo[T any](x StateField[T], y T) error {
return x.AssertEqual(y) // panics
}
func main() {
r1 := RestartedAfter(1)
r2 := RestartedAfter(2)
err := compareTwo[RestartedAfter](r1, r2)
if err != nil {
os.Exit(1)
}
}
This example however panics. I get the following message: panic: interface conversion: main.StateField[go.shape.int_0] is main.RestartedAfter, not main.RestartedAfter (types from different scopes)
.
Any ideas of what's wrong?
I believe this is a bug described here: https://github.com/golang/go/issues/53376
To fix in current version you can reassign the variables:
func compareTwo[T any](x StateField[T], y T) error {
a := x
b := y
return a.AssertEqual(b)
}
It works without the fix in latest dev branch: https://go.dev/play/p/KAPDHQW8RWH?v=gotip