I'll post the code example that I am currently working on. I got the error:
error: invalid operation: cannot call non-function fn (variable of type MF constrained by MapFunc)
Is it possible to use constraints that contain different function signatures to be used in this way? (I would like to understand how to get what I have written to work first if at all possible.)
Here is the example:
package main
import "fmt"
// MapFunc constraint used in Funcy
type MapFunc interface {
func(s string, ss []string) []string | func(s string, ss []string) []bool
}
// MapFuncType used for Funcy return constraint
type MapFuncType interface {
string | bool
}
// Funcy preforms map operation on generic map functions
func Funcy[MF MapFunc, MFT MapFuncType](s string, ss []string, fn MF) []MFT {
return fn(s, ss)
// error: invalid operation: cannot call non-function fn (variable of type
// MF constrained by MapFunc)
}
// appendTo adds given string to the end of each index of given slice of strings
// Ex. appendTo("_", []string{"append", "to"}) --> []string{"append_", "to_"}
func appendTo(s string, ss []string) []string {
var slice []string
for _, v := range ss {
slice = append(slice, v s)
}
return slice
}
// isMatch checks given string against each index in given string slice for a
// match
// Ex. isMatch("hi", []string{"hello", "hi"}) --> []bool{false, true}
func isMatch(s string, ss []string) []bool {
var slice []bool
for _, v := range ss {
slice = append(slice, s == v)
}
return slice
}
func main() {
slice1 := []string{"append", "to"}
slice2 := []string{"hello", "hi"}
fmt.Println(Funcy(slice1, appendTo))
// want: []string{"append_", "to_"}
// got: error: cannot infer MFT
fmt.Println(Funcy(slice2, isMatch))
//[]bool{false, true}
// got: error: cannot infer MFT
}
CodePudding user response:
When you constrain the type param MF
to MapFunc
, you can't call fn
because the function types in MapFunc
's type set don't have the same signature. They have different return types []string
and []bool
.
So the variable of type fn
effectively does not support being called, and you get the (slightly cryptic) error message "cannot call non-function fn".
More formally, only a value that has a core type of type function can be called, but the constraint MapFunc
doesn't have a core type.
The fix would be to parametrize MapFunc
and use that type parameter as the return value, so that upon instantiation, it would have a core type:
type MapFunc[T MapFuncType] interface {
func(s string, ss []string) []T
}
And instantiate the constraint with MFT
in Funcy
:
func Funcy[MF MapFunc[MFT], MFT MapFuncType](s string, ss []string, fn MF) []MFT {
return fn(s, ss)
}
Playground: https://go.dev/play/p/q88aJLgnzXZ