As the error suggests, methods cannot have type parameters
of their own as per the latest design. However, they can use the generics from the interface or struct they belong to.
What you need is to specify the type parameter on the interface type as follows:
type Iterator[T any] interface {
// ...
}
and then use the T
as any other type parameter in methods within the interface body. For example:
package main
import "fmt"
type Iterator[T any] interface {
ForEachRemaining(action func(T) error) error
// other methods
}
func main() {
fmt.Println("This program compiles")
}
Try it on Go playground.
When you constrain both X
and Y
to any
, you lose all interface-implementor relationship. The only thing that is known at compile time is that X
and Y
are different types, and you can't assign one to the another within the function body.
A way to make it compile is to use an explicit assertion:
func Fill[X, Y any](slice []X) {
for i := range slice {
slice[i] = any(*new(Y)).(X)
}
}
But this panics if Y
doesn't really implement X
, as in your case, since it is *sync.Mutex
(pointer type) that implements sync.Locker
.
Moreover, when Y
is instantiated with a pointer type, you lose information about the base type, and therefore the zero value, including *new(Y)
would be nil
, so you don't really have a baseline improvement over make
(just typed nils vs. nil interfaces).
What you would like to do is to constrain Y
to X
, like Fill[X any, Y X](slice []X)
but this is not possible because 1) a type parameter can't be used as a constraint; and/or 2) a constraint can't embed a type parameter directly. It also initializes nils as the above.
A better solution is to use a constructor function instead of a second type parameter:
func main() {
xs := make([]sync.Locker, 10)
Fill(xs, func() sync.Locker { return &sync.Mutex{} })
}
func Fill[X any](slice []X, f func() X) {
for i := range slice {
slice[i] = f()
}
}
Best Answer
As of Go 1.18 you can write a generic function
Print
as below:Output: