我希望能够创建一个结构体,该结构体的字段可以保存任何类型的值,只要该类型可以与常用的比较运算符( <
、 <=
、 >
等)进行比较...)。我知道有contraints.Ordered
,但该接口(interface)仅限于用作类型约束。
以下是我想要使用此界面的示例:
func TestMergeSort(t *testing.T) {
type TestCase[T constraints.Ordered] struct {
input []T
expected []T
}
intTests := map[string]TestCase[int] {
"#1": {
input: []int{3,2,5,1,4,6},
expected: []int{1,2,3,4,5,6},
},
}
stringTests := map[string]TestCase[string] {
"#2": {
input: []string{"hello","bonjour"},
expected: []string{"bonjour","hello"},
},
}
// test int sorting
for name, test := range intTests {
t.Run(name, func(t *testing.T) {
output := MergeSort(test.input)
if !cmp.Equal(test.expected, output) {
t.Fatalf(`Expected %v got %v`, test.expected, output)
}
})
}
// test string sorting
for name, test := range stringTests {
t.Run(name, func(t *testing.T) {
output := MergeSort(test.input)
if !cmp.Equal(test.expected, output) {
t.Fatalf(`Expected %v got %v`, test.expected, output)
}
})
}
}
我希望能够将 int 和 string 测试用例分组到单个变量下。但这似乎不可能使用 constraints.Ordered
的泛型约束,因为我必须先实例化泛型类型,然后才能使用它。
理想情况下,我想将其简化为如下所示:
func TestMergeSortTable(t *testing.T) {
// What I'm looking for is something that can replace the `Sortable` interface example below
type TestCase struct {
input []Sortable
expected []Sortable
}
tests := map[string]TestCase {
"#1": {
input: []int{3,2,5,1,4,6},
expected: []int{1,2,3,4,5,6},
},
"#2": {
input: []string{"hello","bonjour"},
expected: []string{"bonjour","hello"},
},
}
// test int and string sorting in a single loop
for name, test := range tests {
t.Run(name, func(t *testing.T) {
output := MergeSort(test.input)
if !cmp.Equal(test.expected, output) {
t.Fatalf(`Expected %v got %v`, test.expected, output)
}
})
}
}
PS: MergeSort
的函数签名如果需要的话
func MergeSort[T constraints.Ordered](arr []T)(res []T) {
// sorting logic here
}
最佳答案
具有唯一类型参数的泛型类型的实例化是不同的类型。我们需要一种方法来创建包含这些不同类型元素的 slice 。
Go 的类型参数功能不提供表示某种类型的所有实例化的非泛型类型,但 Go 确实具有我们从 Go 诞生之初就知道的基本接口(interface)功能。这就是我们在这里使用的。
我们定义一个 interface { run(*testing.T) }
slice ,并用实例化类型的值填充该 slice ,其中该类型具有所需的 run
方法。
type sortTestCase[T constraints.Ordered] struct {
input, want []T
}
func (tc sortTestCase[T]) run(t *testing.T) {
got := MergeSort(tc.input)
if !cmp.Equal(tc.want, got) {
t.Fatalf(`Expected %v got %v`, tc.want, got)
}
}
func TestSort(t *testing.T) {
testCases := map[string]interface{ run(t *testing.T) }{
"ints": sortTestCase[int]{
input: []int{3, 2, 5, 1, 4, 6},
want: []int{1, 2, 3, 4, 5, 6},
},
"strings": sortTestCase[string]{
input: []string{"hello", "bonjour"},
want: []string{"bonjour", "hello"},
},
}
for n, tc := range testCases {
t.Run(n, tc.run)
}
}
Run the test on the playground!
评论表明可以通过使用接口(interface)的命名类型而不是匿名接口(interface)来改进答案。这是包含建议更改的代码。
type sortTestCase[T constraints.Ordered] struct {
input, want []T
}
func (tc sortTestCase[T]) run(t *testing.T) {
got := MergeSort(tc.input)
if !cmp.Equal(tc.want, got) {
t.Fatalf(`Expected %v got %v`, tc.want, got)
}
}
func TestSort(t *testing.T) {
type runtester interface{ run(t *testing.T) }
var sortTestCases = map[string]runtester{
"ints": sortTestCase[int]{
input: []int{3, 2, 5, 1, 4, 6},
want: []int{1, 2, 3, 4, 5, 6},
},
"strings": sortTestCase[string]{
input: []string{"hello", "bonjour"},
want: []string{"bonjour", "hello"},
},
}
for n, tc := range testCases {
t.Run(n, tc.run)
}
}
关于sorting - 可以在类型约束之外使用的有序类型的 Go 接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77441696/