I am trying to understand generics implementation in go1.18. In my test example, I am storing a series of test cases and attempting to call a function variable. Unfortunately, I am getting an error in the EvalCases function when I try to use the variable tc.input, I receive the following error:
cannot use input (variable of type T constrained by Inputer) as type string in argument to fn
Why am I receiving that error, and how do I fix it?
import (
"fmt"
"strconv"
)
type BoolCase func(string) bool
type Inputer interface {
int | float64 | ~string
}
type Wanter interface {
Inputer | bool
}
type TestCase[T Inputer, U Wanter] struct {
input T
want U
}
type TestConditions[T Inputer, U Wanter] map[string]TestCase[T, U]
// IsNumeric validates that a string is either a valid int64 or float64
func IsNumeric(s string) bool {
_, err := strconv.ParseFloat(s, 64)
return err == nil
}
func EvalCases[T Inputer, U Wanter](cases TestConditions[T, U], fn BoolCase) {
for name, tc := range cases {
input := T(tc.input)
want := tc.want
// Error: cannot use input (variable of type T constrained by Inputer) as type string in argument to fn
got := fn(input)
fmt.Printf("name: %-20s | input: %-10v | want: %-10v | got: %v\n", name, input, want, got)
}
}
func main() {
var cases = TestConditions[string, bool]{
"empty": {input: "", want: false},
"integer": {input: "123", want: true},
"float": {input: "123.456", want: true},
}
fn := IsNumeric
EvalCases(cases, fn)
}
CodePudding user response:
Why am I receiving that error
Because fn
is a BoolFunc
, which is a func(string) bool
, thus requires a string
as parameter, but input
is of type T
. Furthermore, by your definition, T
satisfies the Inputer
constraint, and thus can also assume type int
, float64
or any non-string
type which has string
as its underlying type (~string
) none of which implicitly cast to string
.
how do I fix it?
You need to change the definition of BoolCase
to itself have a generic type parameter for its one parameter. You could constraint it to Inputer
, but you could also use any
(interface{}
).
type BoolCase[T any] func(T) bool
Then make sure to serve this generic type parameter in the signature of function EvalCases
:
func EvalCases[T Inputer, U Wanter](cases TestConditions[T, U], fn BoolCase[T])