Home  >  Article  >  Backend Development  >  How to Fill a Slice of Interfaces with Concrete Types in Golang Generics?

How to Fill a Slice of Interfaces with Concrete Types in Golang Generics?

Barbara Streisand
Barbara StreisandOriginal
2024-10-26 05:38:30358browse

How to Fill a Slice of Interfaces with Concrete Types in Golang Generics?

Golang Generics: Using Interface and Concrete Type Concurrently

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.

A Possible Solution

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 Better Alternative

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!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn