Home > Software design >  Cannot use golang generics variable in function call
Cannot use golang generics variable in function call

Time:03-20

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])

https://go.dev/play/p/RdjQXJ0WpDh

  • Related