Is it possible to write a generic type constraint so that the type contains a function returning the same type or is it the same problem as with normal interfaces? Example use-case would be a builder with chainable methods.
Let's say I have a builder IntFoo
which has a SetFoo
method responsible for setting the foo
field to some value. Playground link
type IntFoo struct {
foo int
}
func (me *IntFoo) SetFoo(foo int) *IntFoo {
me.foo = foo
return me
}
Now I might have several builders like this one with different types and I'd like to define a constraint like this:
type Builder[F any] interface {
SetFoo(F) Builder[F] // this return type is problematic
}
and some function consuming the Builder-constrained type like so:
// some generic demo function
func demo[E Builder[F], F any](builder E, foo F) {
builder.SetFoo(foo)
return
}
Trying to call the demo function
e := &IntFoo{}
demo(e, 2)
results in an error:
[compiler InvalidTypeArg] [E] *IntFoo does not implement Builder[int] (wrong type for method SetFoo)
have SetFoo(foo int) *IntFoo
want SetFoo(int) Builder[int]
CodePudding user response:
You want to return the original type, not the interface
you define for the method. So this will work:
type Builder[F any, E any] interface {
SetFoo(F) E
}
and reworking demo
slightly:
func demo[F any, E Builder[F, E]](builder E, foo F) E {
return builder.SetFoo(foo)
}
https://go.dev/play/p/jkD9xTUDbjV
result := demo(e, 2)
fmt.Printf("%[1]T : %[1]v\n", result) // *main.IntFoo : &{2}