Convert func(T) to func(any)

Issue

I want to be able to enforce similarity between two fields of a struct but also have several of these structs in a map or slice.

Here’s a simplified example of my problem:

package main

type foo[T any] struct {
    f func(T)
    v T
}

type bar struct {
    x []*foo[any]
}

func baz[T any](b *bar, f func(T)) {
    b.x = append(b.x, &foo[any]{f})
}

func main() {
    var b bar
    baz(&b, func(i int) {})
}

The compiler complains

./prog.go:13:30: cannot use f (variable of type func(T)) as type func(any) in struct literal

The funny thing is that this can work if I didn’t need to have a function pointer in the struct. See https://go.dev/play/p/qXTmaa9PuVe

So, is there a way for me to turn a T into an any?

I know I could do this with interface{}s and use reflect to enforce what I want, but I’m sure it’s possible with only generics.

The context in case there is a way around my problem is that I’m making a flag package. The important structs look like this:

type flag[T any] struct {
    value T
    parse func(in string) (T, error)
    // Other fields removed for simplicity...
}

type FlagSet struct {
    // could flag[any] be replaced with a better answer?
    flags map[string]*flag[any]
    // Other fields removed for simplicity...
}

Solution

but also have several of these structs in a map or slice

You cannot do this (in a type safe way). All values of e.g. a slice must have the same element type. If you want to store different ones you have to resort to interface{} and type switch later.

If you use the correct technical term parametric polymorphism instead of "generics" which doesn’t explain what is going on you will see why func(T) and func(any) are different, unconvertable types.

So, is there a way for me to turn a T into an any?

No, there was no pre-"generics" way and there is no post-"generics" way. It helps to think of "turn into" as what Go allows: "type conversion" and "assignment". You can assign any variable of type T to a variable of type any.

You might overcome your issue by using an adaptor function (closure):

w := func(a any){ f(a.(T)) }
b.x = append(b.x, &foo[any]{w})

Answered By – Volker

Answer Checked By – Pedro (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.