I am trying to write the following function:
func Fill[X any](slice []*X){
for i := range slice {
slice[i] = new(X)
}
}
xs := make([]*int, 10) // fill with nils
Fill(xs) // now fill with new(int)
That works fine but… if I want to use a slice of interfaces and provide a concrete type?
func Fill[X, Y any](slice []X){
for i := range slice {
slice[i] = new(Y) // not work!
}
}
xs := make([]sync.Locker, 10) // fill with nils
Fill[sync.Locker,sync.Mutex](xs) // ouch
I try some combinations without success, is there a way or go1.18 does not support such relations?
Best Answer
When you constrain both
X
andY
toany
, you lose all interface-implementor relationship. The only thing that is known at compile time is thatX
andY
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:
But this panics if
Y
doesn't really implementX
, as in your case, since it is*sync.Mutex
(pointer type) that implementssync.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 benil
, so you don't really have a baseline improvement overmake
(just typed nils vs. nil interfaces).What you would like to do is to constrain
Y
toX
, likeFill[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: