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

Barbara Streisand
Release: 2024-10-26 05:38:30
Original
368 people have browsed it

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>
Copy after login

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>
Copy after login

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>
Copy after login

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>
Copy after login

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!

source:php.cn
Statement of this Website
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
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!