Home  >  Article  >  Backend Development  >  How to Fill a Slice with Concrete Implementations Using Golang Generics and Interfaces?

How to Fill a Slice with Concrete Implementations Using Golang Generics and Interfaces?

Mary-Kate Olsen
Mary-Kate OlsenOriginal
2024-10-26 10:33:02704browse

How to Fill a Slice with Concrete Implementations Using Golang Generics and Interfaces?

Golang Generics: Combining Interfaces and Concrete Implementations

In Go 1.18, generics allow developers to define functions and data structures that operate on a wider range of types. However, a specific scenario has emerged where users seek to use generics with interfaces while also providing a concrete type for generic type parameters.

Issue

Consider the following function that aims to populate a slice with new instances of a concrete type:

<code class="go">func Fill[X any](slice []*X) {
   for i := range slice {
      slice[i] = new(X)
   }
}</code>

This function works as expected when filling a slice of pointers to a specific type, such as []*int. However, if the slice consists of interfaces and the function is called with a concrete type for the generic parameter, compilation fails.

<code class="go">xs := make([]sync.Locker, 10) // fill with nils
Fill[sync.Locker,sync.Mutex](xs) // ouch</code>

Cause

The issue arises because constraining both type parameters X and Y to any removes the relationship between the interface and its concrete implementation. At compile time, it is only known that X and Y are distinct types.

Solution

To address this problem, an explicit assertion can be used:

<code class="go">func Fill[X, Y any](slice []X) {
    for i := range slice {
        slice[i] = any(*new(Y)).(X)
    }
}</code>

However, this solution introduces potential runtime panics if Y does not implement X. Moreover, if Y is a pointer type, the base type information is lost, resulting in nil values instead of instances of the desired concrete type.

A better approach is to use a constructor function instead of a second generic parameter, as demonstrated below:

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

This solution provides a more robust and idiomatic way to fill a slice with instances of a specific concrete type while maintaining type safety.

The above is the detailed content of How to Fill a Slice with Concrete Implementations Using Golang Generics and Interfaces?. 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