可在类型约束之外使用的有序类型的 Go 接口?

问题描述 投票:0回答:1

我希望能够创建一个结构体,该结构体具有一个可以保存任何类型值的字段,只要该类型可以与通常的比较运算符(

<
<=
>
等进行比较)。 .)。我知道有
contraints.Ordered
,但该接口仅限于用作类型约束。

这是我想使用此界面的示例:

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
}
sorting go generics interface
1个回答
0
投票

为测试用例声明一个接口,而不是切片元素。将运行逻辑实现为测试用例方法。

type sortTestCase[T constraints.Ordered] struct {
    name  string
    input []T
    want  []T
}

func (tc sortTestCase[T]) run(t *testing.T) {
    t.Run(tc.name, func(t *testing.T) {
        got := slices.Clone(tc.input)
        slices.Sort(got)
        if !reflect.DeepEqual(got, tc.want) {
            t.Fatalf(`got %v want %v`, got, tc.want)
        }
    })
}

var sortTestCases = []interface{ run(t *testing.T) }{
    sortTestCase[int]{
        name:  "ints",
        input: []int{3, 2, 5, 1, 4, 6},
        want:  []int{1, 2, 3, 4, 5, 6},
    },
    sortTestCase[string]{
        name:  "strings",
        input: []string{"hello", "bonjour"},
        want:  []string{"bonjour", "hello"},
    },
}

func TestSort(t *testing.T) {
    for _, tc := range sortTestCases {
        tc.run(t)
    }
}

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

© www.soinside.com 2019 - 2024. All rights reserved.