'Convert func(T) to func(any) [duplicate]
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: f})
}
func main() {
var b bar
baz(&b, func() int { return 0 })
}
The compiler complains
./prog.go:13:33: 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...
}
The question was closed so I have to put the answer to the second part of my question here
could flag[any] be replaced with a better answer?
The answer to the above is yes.
Solution:
Originally I though something like: "a func()
fits a func()
and an any
fits a T
so why can't I have a func() T
fit a func() any
?" Of course the reason is a func() any
is not an any
and so it cannot hold a func() T
.
Instead, you can do the following:
package main
type foo[T any] struct {
f func() T
v T
}
func (f *foo[_]) set() {
f.v = f.f()
}
type anyfoo interface {
set()
}
type bar struct {
x []anyfoo
}
func baz[T any](b *bar, f func() T) {
b.x = append(b.x, &foo[T]{f: f})
}
func main() {
var b bar
baz(&b, func() int { return 0 })
}
Solution 1:[1]
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})
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | blackgreen |