Home > Mobile >  Why do Go generics fail when function returns a function?
Why do Go generics fail when function returns a function?

Time:12-05

I've just started trying out generics on Go, and I run into a situation which I don't fully understand why it's failing.

I've refactored the following function, from this:

func PositivePercentageAbove(above int) func(list []uint8) bool {
    return func(list []uint8) bool {
        acum := 0
        for _, x := range list {
            acum  = int(x)
        }
        return (float64(acum) / float64(len(list)) * 100) >= float64(above)
    }
}

into this:

func PositivePercentageAbove[T constraints.Integer](above int) func(list []T) bool {
    return func(list []T) bool {
        acum := 0
        for _, x := range list {
            acum  = int(x)
        }
        return (float64(acum) / float64(len(list)) * 100) >= float64(above)
    }
}

The unit test for this function is failing with error: tests/utils/NumberUtils_test.go:82:50: cannot infer T . The source is:

func Test_TruePercentageAbove(t *testing.T) {
    tables := []struct {
        percentage int
        list       []uint8
        output     bool
    }{
        {percentage: 100, list: []uint8{1, 1, 1, 1}, output: true},
        {percentage: 100, list: []uint8{1, 1, 0, 1}, output: false},
        {percentage: 80, list: []uint8{1, 1, 1, 1, 0}, output: true},
        {percentage: 90, list: []uint8{1, 1, 1, 1, 0}, output: false},
        {percentage: 100, list: []uint8{1, 1, 1, 1, 0}, output: false},
        {percentage: 40, list: []uint8{0, 1, 0, 1, 0, 1}, output: true},
        {percentage: 60, list: []uint8{0, 1, 0, 1, 0, 1}, output: false},
        {percentage: 70, list: []uint8{0, 1, 0, 1, 0, 1}, output: false},
    }

    for _, table := range tables {
        result := utils.PositivePercentageAbove(table.percentage)(table.list)

        if result != table.output {
            t.Errorf("Slice %v with percentage above %v expected to return %v but returned %v", table.list, table.percentage, table.output, result)
        }
    }
}

I've changed similar functions from int to generics, I'm not sure why this one in particular is not working. I assume it might be somehow related with the function returning another function, but I can't figure exactly why. Thanks.

CodePudding user response:

As often, the answer lies in the Type Parameters proposal:

The only type arguments that can be inferred are those that are used for the types of the function‘s (non-type) input parameters. If there are some type parameters that are used only for the function’s result parameter types, or only in the body of the function, then those type arguments cannot be inferred using function argument type inference.

In the case of

func PositivePercentageAbove[T constraints.Integer](above int) func(list []T) bool

because type parameter T does not appear in the parameter list, the corresponding type argument cannot be inferred.

  • Related