Golang generics: how to define generic types that "mix'n'match" pointer methods from several other types

Viewed 426

I want to define custom types that have two methods, call them CompliesWith and Update. These types are struct that hold a value of a generic type.

The Update method needs to be a pointer method so it can update the value of the instance it's called on.

I need several different types that are combinations of a few different implementations of CompliesWith and Update. For example:

  • CompliesWith defined for numbers that compares with >=, <=, == and so on
  • Update that overwrites with a new value, overwrites only if the current one complies with, adds the new value to the current one, etc.

I want to have a few types that define the various CompliesWith methods, and a few types that define the various Update methods, and then define types that are combinations of those and inherit the two methods.

The Update methods though need to call CompliesWith so its type must implement that interface. I tried many many things, here's the one that's least bad from the attempts I came up with: https://go.dev/play/p/ABTeZzVcWes

Basically I've defined a "compliancer" type and then an "updater" type.

The unsolved problem with it is, as I've indicated in the comments in the code, is I can't find a way to define the type constraint that allows me to access the CompliesWith method as well as the value struct field itself. There is no way to define an interface for struct fields, I can't use a pointer method, since the type I pass won't implement that interface (its pointer does), and I can't directly access the struct field using the generic type parameter. Hopefully the code makes this clear.

The workaround I've come up with is to define a pointer method to access the struct field and a separate interface for that pointer type, which is not used as a constraint but in a type assertion. That's a bit ugly in my opinion. I want to know if there's a better way to achieve what I want to achieve.

I'd love to be able to cast the embedded struct of generic type T into the same underlying struct type so I can access the field, like that and I don't understand why I can't:

func (u *updaterBase[C, T]) Set(v T) {    
    // *** why doesn't this work: cannot assign to interface{}(u.c).(struct{base[T]}).value (value of type T constrained by any)
    // interface{}(u.c).(struct{ base[T] }).value = v

    // *** why doesn't this work: cannot assign to struct{base[T]}(u.c).value (value of type T constrained by any)
    // struct{ base[T] }(u.c).value = v
}
0 Answers
Related