In Go 1.18, generics have introduced new possibilities for type handling. However, certain scenarios may pose challenges when using interfaces and concrete types together.
One such scenario arises when attempting to create a function like this:
<code class="go">func Fill[X any](slice []*X){ for i := range slice { slice[i] = new(X) } }</code>
This function is meant to fill a slice of interfaces with concrete types. For instance, an array of *int can be filled with new(int) using this function.
The issue arises when trying to fill a slice of interfaces with a concrete type that implements the interface. Consider this code:
<code class="go">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</code>
In this case, the function does not work because constraining both X and Y to any breaks the relationship between the interface and the implementing type. The compiler only recognizes that X and Y are distinct types at compile time.
There is a workaround to make the code compile using an explicit assertion:
<code class="go">func Fill[X, Y any](slice []X) { for i := range slice { slice[i] = any(*new(Y)).(X) } }</code>
However, this solution has a significant drawback: it panics if Y does not implement X, like with sync.Locker and sync.Mutex. Additionally, using a pointer type for Y results in nil values since it loses the base type and zero value information.
A more robust solution is to use a constructor function instead of the second type parameter:
<code class="go">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() } }</code>
In this approach, the function takes a slice of type X and a constructor function. The constructor function creates an instance of type X, filling the slice with concrete instances.
The above is the detailed content of How to Fill a Slice of Interfaces with Concrete Types in Golang Generics?. For more information, please follow other related articles on the PHP Chinese website!