我正在通过修改我为处理切片而创建的库来尝试泛型。我有一个Difference函数,它接受切片并返回仅在其中一个切片中找到的唯一元素的列表。
我修改了该函数以使用泛型,并且我正在尝试使用不同类型(例如字符串和整数)编写单元测试,但在联合类型方面遇到了麻烦。这就是我现在所拥有的:
\ntype testDifferenceInput[T comparable] [][]T\ntype testDifferenceOutput[T comparable] []T\ntype testDifference[T comparable] struct {\n input testDifferenceInput[T]\n output testDifferenceOutput[T]\n}\n\nfunc TestDifference(t *testing.T) {\n for i, tt := range []testDifference[int] {\n testDifference[int]{\n input: testDifferenceInput[int]{\n []int{1, 2, 3, 3, 4},\n []int{1, 2, 5},\n []int{1, 3, 6},\n },\n output: []int{4, 5, 6},\n },\n } {\n t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {\n actual := Difference(tt.input...)\n\n if !isEqual(actual, tt.output) {\n t.Errorf("expected: %v %T, received: %v %T", tt.output, tt.output, actual, actual)\n }\n })\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n我希望能够在同一个表测试中测试 int 或 string。这是我尝试过的:
\ntype intOrString interface {\n int | string\n}\ntype testDifferenceInput[T comparable] [][]T\ntype testDifferenceOutput[T comparable] []T\ntype testDifference[T comparable] struct {\n input testDifferenceInput[T]\n output testDifferenceOutput[T]\n}\n\nfunc TestDifference(t *testing.T) {\n for i, tt := range []testDifference[intOrString] {\n testDifference[int]{\n input: testDifferenceInput[int]{\n []int{1, 2, 3, 3, 4},\n []int{1, 2, 5},\n []int{1, 3, 6},\n },\n output: []int{4, 5, 6},\n },\n testDifference[string]{\n input: testDifferenceInput[string]{\n []string{"1", "2", "3", "3", "4"},\n []string{"1", "2", "5"},\n []string{"1", "3", "6"},\n },\n output: []string{"4", "5", "6"},\n },\n } {\n t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {\n actual := Difference(tt.input...)\n\n if !isEqual(actual, tt.output) {\n t.Errorf("expected: %v %T, received: %v %T", tt.output, tt.output, actual, actual)\n }\n })\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n但是,运行此程序时,我收到以下错误:
\n$ go version\ngo version dev.go2go-55626ee50b linux/amd64\n\n$ go tool go2go test\narrayOperations_unit_test.go2:142:6: expected \';\', found \'|\' (and 5 more errors)\nRun Code Online (Sandbox Code Playgroud)\n为什么它抱怨我的intOrString界面?
编辑 #1 - 在@Nulo 的帮助下,我可以确认gotip确实有效,而且我现在明白为什么我不能用作intOrString类型 - 它应该是一个约束。
然而,在我的表测试中找到某种方法来混合整数和字符串仍然是件好事......
\n$ gotip version\ngo version devel go1.18-c812b97 Fri Oct 29 22:29:31 2021 +0000 linux/amd64\n\n$ gotip test\n# github.com/adam-hanna/arrayOperations/go2 [github.com/adam-hanna/arrayOperations/go2.test]\n./arrayOperations_unit_test.go:152:39: interface contains type constraints\n./arrayOperations_unit_test.go:152:39: intOrString does not satisfy intOrString\n./arrayOperations_unit_test.go:155:6: incompatible type: cannot use []int{\xe2\x80\xa6} (value of type []int) as []intOrString value\n./arrayOperations_unit_test.go:156:6: incompatible type: cannot use []int{\xe2\x80\xa6} (value of type []int) as []intOrString value\n./arrayOperations_unit_test.go:157:6: incompatible type: cannot use []int{\xe2\x80\xa6} (value of type []int) as []intOrString value\n./arrayOperations_unit_test.go:159:13: incompatible type: cannot use []int{\xe2\x80\xa6} (value of type []int) as testDifferenceOutput[intOrString] value\n./arrayOperations_unit_test.go:163:6: incompatible type: cannot use []string{\xe2\x80\xa6} (value of type []string) as []intOrString value\n./arrayOperations_unit_test.go:164:6: incompatible type: cannot use []string{\xe2\x80\xa6} (value of type []string) as []intOrString value\n./arrayOperations_unit_test.go:165:6: incompatible type: cannot use []string{\xe2\x80\xa6} (value of type []string) as []intOrString value\n./arrayOperations_unit_test.go:167:13: incompatible type: cannot use []string{\xe2\x80\xa6} (value of type []string) as testDifferenceOutput[intOrString] value\n./arrayOperations_unit_test.go:152:39: too many errors\nFAIL github.com/adam-hanna/arrayOperations/go2 [build failed]\nRun Code Online (Sandbox Code Playgroud)\n
bla*_*een 29
如果您因为它的通用标题(不是双关语)而遇到此问答,这里有一个关于工会的快速入门:
\nT将仅限于联合中的类型~例如:
\ntype intOrString interface {\n int | string\n}\n\nfunc Foo[T intOrString](x T) {\n // x can be int or string\n}\nRun Code Online (Sandbox Code Playgroud)\n现在讨论OP的问题,并提供更多细节:
\n通过包含类型集,intOrString成为接口约束,并且明确不支持将其用作类型。允许约束作为普通接口类型:
\n\n我们现在不建议使用此功能,但可以在该语言的更高版本中考虑该功能。
\n
因此,要做的第一件事就是用作intOrString实际约束,因此在类型参数列表中使用它。下面我替换comparable为intOrString:
type testDifferenceInput[T intOrString] [][]T\ntype testDifferenceOutput[T intOrString] []T\ntype testDifference[T intOrString] struct {\n input testDifferenceInput[T]\n output testDifferenceOutput[T]\n}\nRun Code Online (Sandbox Code Playgroud)\n这也意味着您不能使用约束来实例化具体类型作为测试切片:
\n// bad: using intOrString to instantiate a parametrized type\n[]testDifference[intOrString]\nRun Code Online (Sandbox Code Playgroud)\n您遇到的第二个问题是测试切片包含两个不相关类型的结构。一是testDifference[int],一是testDifference[string]。尽管类型testDifference本身使用联合约束进行参数化,但其具体实例化并不是同一类型。另请参阅此了解更多详细信息。
如果您需要一个包含不同类型的切片,您唯一的选择是[]interface{}(或[]any) ...或者,您只需分隔切片:
ttInts := []testDifference[int]{ testDifference[int]{...}, /* etc. */ }\nttStrs := []testDifference[string]{ testDifference[string]{...}, /* etc. */ }\nRun Code Online (Sandbox Code Playgroud)\n仅类型集中所有类型支持的操作。基于类型集的操作:
\n\n\n规则是泛型函数可以以parameter\xe2\x80\x98s 约束的类型集的每个成员允许的任何方式使用类型为类型参数的值。
\n
如果存在类似约束,则orint | string允许执行哪些操作?简而言之:intstring
var foo T)T(x)和x.(T),在适当的情况下==,!=)<、<=、>和>=)+运营商因此,您可以有一个intOrString约束,但使用它的函数(包括您的 func Difference)仅限于这些操作。例如:
type intOrString interface {\n int | string\n}\n\nfunc beforeIntOrString[T intOrString](a, b T) bool {\n return a < b\n}\n\nfunc sumIntOrString[T intOrString](a, b T) T {\n return a + b\n}\n\nfunc main() {\n fmt.Println(beforeIntOrString("foo", "bar")) // false\n fmt.Println(beforeIntOrString(4, 5)) // true\n\n fmt.Println(sumIntOrString("foo", "bar")) // foobar\n fmt.Println(sumIntOrString(10, 5)) // 15\n}\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
17011 次 |
| 最近记录: |