pmeier
(Philip Meier)
April 1, 2025, 10:00am
1
Consider the following snippet (playground )
package main
import "fmt"
type Foo struct{}
func foo() (Foo, error) {
return Foo{}, nil
}
type Bar struct{}
func bar() (Bar, error) {
return Bar{}, nil
}
func Wrap(fn func() (any, error)) func() string {
return func() string {
d, err := fn()
if err != nil {
return err.Error()
} else {
return fmt.Sprint(d)
}
}
}
func main() {
_ = Wrap(foo)
_ = Wrap(bar)
}
Trying to compile this yields the following error:
./prog.go:29:11: cannot use foo (value of type func() (Foo, error)) as func() (any, error) value in argument to Wrap
./prog.go:30:11: cannot use bar (value of type func() (Bar, error)) as func() (any, error) value in argument to Wrap
Any way to change the signature of Wrap
to allow for this? A workaround currently is to do
func main() {
_ = Wrap(func() (any, error) { return foo() })
}
but that is quite cumbersome.
pekim
(Mike D Pilsbury)
April 1, 2025, 10:44am
2
You could use generics.
Replace
func Wrap(fn func() (any, error)) func() string {
with
func Wrap[T any](fn func() (T, error)) func() string {
3 Likes
blogscot
(Iain Diamond)
April 1, 2025, 10:53am
3
If you’re using generics you could create a generic type more restrictive than any
. For example,
func Wrap[T Foo | Bar](fn func() (T, error)) func() string {
...
}
1 Like
pmeier
(Philip Meier)
April 1, 2025, 11:33am
4
Thanks for the suggestion, but there are actually quite a few types that would make this cumbersome again. Since the implementation of Wrap
actually does work with any
object, there is no need to restrict it artificially.
pmeier:
package main
import "fmt"
type Foo struct{}
func foo() (Foo, error) {
return Foo{}, nil
}
type Bar struct{}
func bar() (Bar, error) {
return Bar{}, nil
}
func Wrap(fn func() (any, error)) func() string {
return func() string {
d, err := fn()
if err != nil {
return err.Error()
} else {
return fmt.Sprint(d)
}
}
}
func main() {
_ = Wrap(foo)
_ = Wrap(bar)
}
Trying to compile this yields the following error:
./prog.go:29:11: cannot use foo (value of type func() (Foo, error)) as func() (any, error) value in argument to Wrap
./prog.go:30:11: cannot use bar (value of type func() (Bar, error)) as func() (any, error) value in argument to Wrap
Any way to change the signature of Wrap
to allow for this? A workaround currently is to do
func main() {
_ = Wrap(func() (any, error) { return foo() })
}
but that is quite cumbersome.
Yeah, this happens because Go doesn’t allow implicit conversion of concrete return types to any
. You’ll need to explicitly wrap the function call.
One way to adjust Wrap
is to use generics:
func Wrap[T any](fn func() (T, error)) func() string {
return func() string {
d, err := fn()
if err != nil {
return err.Error()
}
return fmt.Sprint(d)
}
}
This should let you use Wrap(foo)
and Wrap(bar)
without needing the extra wrapper function.