为什么在Go语言中,当函数返回一个函数时,泛型会失败?

huangapple go评论73阅读模式
英文:

Why do Go generics fail when function returns a function?

问题

我刚刚开始尝试在Go语言中使用泛型,并遇到了一个我不太理解为什么会失败的情况。

我从以下函数进行了重构:

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

重构后的代码如下:

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

这个函数的单元测试失败,并显示错误信息:tests/utils/NumberUtils_test.go:82:50: cannot infer T。测试代码如下:

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

我已经将类似的函数从int改为了泛型,但不确定为什么这个特定的函数不起作用。我猜想可能与函数返回另一个函数有关,但我无法确定具体原因。谢谢。

英文:

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.

答案1

得分: 2

通常情况下,答案可以在类型参数提案中找到:

只有用于函数的(非类型)输入参数类型的类型参数可以被推断出来。如果有一些类型参数仅用于函数的结果参数类型,或者仅在函数体中使用,则这些类型参数不能使用函数参数类型推断来推断。

在以下情况下:

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

因为类型参数 T 在参数列表中没有出现,所以对应的类型参数无法被推断。

英文:

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.

huangapple
  • 本文由 发表于 2022年12月5日 21:20:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/74688873.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定