Table of Contents
Question content
Home Backend Development Golang How to instantiate a non-zero pointer to a type parameter using a generic Go?

How to instantiate a non-zero pointer to a type parameter using a generic Go?

Feb 11, 2024 pm 05:36 PM
go language arrangement

如何使用泛型 Go 实例化类型参数的非零指针?

php editor Xigua will introduce to you how to use non-zero pointers of generic instantiation type parameters in the Go language. In Go language, generics are a powerful feature that can increase the flexibility and reusability of code. When we need to instantiate a non-zero pointer in a generic function or method, we can use type assertions and reflection to achieve this. By using these techniques, we can create a non-zero pointer instance at runtime based on the specific type of the type parameter, thereby achieving the flexibility and versatility of generics. Let's take a closer look at the specific implementation method.

Question content

Now that type parameters are available on golang/go:master, I decided to give it a try. It seems I've hit a limitation that I can't find in the type parameters proposal. (Or I must have missed it).

I want to write a function that returns a slice of generic type values ​​with interface type constraints. If the type passed is an implementation with a pointer receiver, how do we instantiate it?

type SetGetter[V any] interface {
    Set(V)
    Get() V
}

// SetGetterSlice turns a slice of type V into a slice of type T,
// with T.Set() called for each entry in values.
func SetGetterSlice[V any, T SetGetter[V]](values []V) []T {
    out := make([]T, len(values))

    for i, v := range values {
        out[i].Set(v) // panic if T has pointer receiver!
    }

    return out
}
Copy after login

When the above SetGetterSlice() function is called using the *Count type as T, this code will call Set(v)## Confusion occurs when #. (Go2go Playground) Not surprising since basically the code creates a slice of nil pointers:

// Count implements SetGetter interface
type Count struct {
    x int
}

func (c *Count) Set(x int) { c.x = x }
func (c *Count) Get() int  { return c.x }

func main() {
    ints := []int{1, 2, 3, 4, 5}

    sgs := SetGetterSlice[int, *Count](ints)
    
    for _, s := range sgs {
        fmt.Println(s.Get())
    }
}
Copy after login

Variation of the same question

This idea doesn't work, I can't seem to find any easy way to instantiate the value pointed to.

  1. out[i] = new(T) will cause compilation to fail because it returns *T, where the type checker expects to see T.
  2. Calling
  3. *new(T) compiles but causes the same runtime panic because new(T) returns **Count here In this case, the pointer to Count is still nil.
  4. Changing the return type to a pointer fragment to
  5. T will cause compilation to fail:
  6. func SetGetterSlice[V any, T SetGetter[V]](values []V) []*T {
        out := make([]*T, len(values))
    
        for i, v := range values {
            out[i] = new(T)
            out[i].Set(v) // panic if T has pointer receiver
        }
    
        return out
    }
    
    func main() {
        ints := []int{1, 2, 3, 4, 5}
    
        SetGetterSlice[int, Count](ints)
        // Count does not satisfy SetGetter[V]: wrong method signature
    }
    Copy after login
Solution

The only solution I've found so far is to require that the constructor be passed to a generic function. But it feels wrong and a bit boring. If

func F(T interface{})() []T is perfectly valid syntax, why is this needed?

func SetGetterSlice[V any, T SetGetter[V]](values []V, constructor func() T) []T {
    out := make([]T, len(values))

    for i, v := range values {
        out[i] = constructor()
        out[i].Set(v)
    }

    return out
}

// ...
func main() {
    ints := []int{1, 2, 3, 4, 5}

    SetGetterSlice[int, *Count](ints, func() *Count { return new(Count) })
}
Copy after login

Summary

My questions (in order of priority):

    Am I overlooking something obvious?
  1. Is this a limitation of generics in Go? Is this as good as it gets?
  2. Is this limitation known or should I raise an issue in the Go project?

Workaround

Basically you have to add a type parameter to the constraint to make

T convertible to its pointer type. In its most basic form, the technique looks like this (with anonymous constraints):

func Foo[T any, PT interface { *T; M() }]() {
    p := PT(new(T))
    p.M() // calling method on non-nil pointer
}
Copy after login

Playground:

https://www.php.cn/link/24aef8cb3281a2422a59b51659f1ad2e

<小时>

Step-by-step solution

Your constraints

SetGetter already declare the type parameter V, so we modify the above example slightly:

// V is your original type param
// T is the additional helper param
type SetGetter[V any, T any] interface {
    Set(V)
    Get() V
    *T
}
Copy after login

Then define the

SetGetterSlice function, whose type parameter is T any, whose purpose is only to instantiate the constraint SetGetter.

You can then cast the expression

&out[i] to a pointer type and successfully call the method on the pointer receiver:

// T is the type with methods with pointer receiver
// PT is the SetGetter constraint with *T
func SetGetterSlice[V any, T any, PT SetGetter[V, T]](values []V) []T {
    out := make([]T, len(values))

    for i, v := range values {
        // out[i] has type T
        // &out[i] has type *T
        // PT constraint includes *T
        p := PT(&out[i]) // valid conversion!
        p.Set(v)         // calling with non-nil pointer receiver
    }

    return out
}
Copy after login

Full program:

CFE57E536C89530D9A8C38E10967A10D

This becomes more verbose because

SetGetterSlice now requires three type parameters: the original V plus T (the type with the pointer receiver) and PT (new constraints). However, when you call the function, you can omit the third - via type inference, the type parameters V and ## required to instantiate PT SetGetter[V,T] #T are all known:

SetGetterSlice[int, Count](ints)
Copy after login
Playground:https://www.php.cn/link/6b061fc28f7473418a006dfa832708b1

The above is the detailed content of How to instantiate a non-zero pointer to a type parameter using a generic Go?. For more information, please follow other related articles on the PHP Chinese website!

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

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Do I need to use flexbox in the center of the Bootstrap picture? Do I need to use flexbox in the center of the Bootstrap picture? Apr 07, 2025 am 09:06 AM

There are many ways to center Bootstrap pictures, and you don’t have to use Flexbox. If you only need to center horizontally, the text-center class is enough; if you need to center vertically or multiple elements, Flexbox or Grid is more suitable. Flexbox is less compatible and may increase complexity, while Grid is more powerful and has a higher learning cost. When choosing a method, you should weigh the pros and cons and choose the most suitable method according to your needs and preferences.

How to calculate c-subscript 3 subscript 5 c-subscript 3 subscript 5 algorithm tutorial How to calculate c-subscript 3 subscript 5 c-subscript 3 subscript 5 algorithm tutorial Apr 03, 2025 pm 10:33 PM

The calculation of C35 is essentially combinatorial mathematics, representing the number of combinations selected from 3 of 5 elements. The calculation formula is C53 = 5! / (3! * 2!), which can be directly calculated by loops to improve efficiency and avoid overflow. In addition, understanding the nature of combinations and mastering efficient calculation methods is crucial to solving many problems in the fields of probability statistics, cryptography, algorithm design, etc.

How to implement adaptive layout of Y-axis position in web annotation? How to implement adaptive layout of Y-axis position in web annotation? Apr 04, 2025 pm 11:30 PM

The Y-axis position adaptive algorithm for web annotation function This article will explore how to implement annotation functions similar to Word documents, especially how to deal with the interval between annotations...

How to elegantly solve the problem of too small spacing of Span tags after a line break? How to elegantly solve the problem of too small spacing of Span tags after a line break? Apr 05, 2025 pm 06:00 PM

How to elegantly handle the spacing of Span tags after a new line In web page layout, you often encounter the need to arrange multiple spans horizontally...

How to make the height of adjacent columns in the Element UI automatically adapt to the content? How to make the height of adjacent columns in the Element UI automatically adapt to the content? Apr 05, 2025 am 06:12 AM

How to make the height of adjacent columns of the same row automatically adapt to the content? In web design, we often encounter this problem: when there are many in a table or row...

Master SQL SELECT statements: A comprehensive guide Master SQL SELECT statements: A comprehensive guide Apr 08, 2025 pm 06:39 PM

SQLSELECT statement Detailed explanation SELECT statement is the most basic and commonly used command in SQL, used to extract data from database tables. The extracted data is presented as a result set. SELECT statement syntax SELECTcolumn1,column2,...FROMtable_nameWHEREconditionORDERBYcolumn_name[ASC|DESC]; SELECT statement component selection clause (SELECT): Specify the column to be retrieved. Use * to select all columns. For example: SELECTfirst_name,last_nameFROMemployees; Source clause (FR

distinct function usage distance function c usage tutorial distinct function usage distance function c usage tutorial Apr 03, 2025 pm 10:27 PM

std::unique removes adjacent duplicate elements in the container and moves them to the end, returning an iterator pointing to the first duplicate element. std::distance calculates the distance between two iterators, that is, the number of elements they point to. These two functions are useful for optimizing code and improving efficiency, but there are also some pitfalls to be paid attention to, such as: std::unique only deals with adjacent duplicate elements. std::distance is less efficient when dealing with non-random access iterators. By mastering these features and best practices, you can fully utilize the power of these two functions.

How to adjust the wordpress article list How to adjust the wordpress article list Apr 20, 2025 am 10:48 AM

There are four ways to adjust the WordPress article list: use theme options, use plugins (such as Post Types Order, WP Post List, Boxy Stuff), use code (add settings in the functions.php file), or modify the WordPress database directly.

See all articles