为了账号安全,请及时绑定邮箱和手机立即绑定

去泛型 - 工会

去泛型 - 工会

Go
墨色风雨 2022-10-10 17:58:06
我正在通过修改我为使用切片创建的库来玩转泛型。我有一个Difference函数,它接受切片并返回仅在其中一个切片中找到的唯一元素列表。我修改了函数以使用泛型,并且我正在尝试使用不同类型(例如字符串和整数)编写单元测试,但在联合类型方面遇到了问题。这是我现在所拥有的:type testDifferenceInput[T comparable] [][]Ttype testDifferenceOutput[T comparable] []Ttype testDifference[T comparable] struct {    input testDifferenceInput[T]    output testDifferenceOutput[T]}func TestDifference(t *testing.T) {        for i, tt := range []testDifference[int] {            testDifference[int]{                input: testDifferenceInput[int]{                    []int{1, 2, 3, 3, 4},                    []int{1, 2, 5},                    []int{1, 3, 6},                },                output: []int{4, 5, 6},            },        } {            t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {                actual := Difference(tt.input...)                if !isEqual(actual, tt.output) {                    t.Errorf("expected: %v %T, received: %v %T", tt.output, tt.output, actual, actual)                }        })    }}我希望能够在同一个表测试中同时测试 int 或 string。这是我尝试过的:type intOrString interface {    int | string}type testDifferenceInput[T comparable] [][]Ttype testDifferenceOutput[T comparable] []Ttype testDifference[T comparable] struct {    input testDifferenceInput[T]    output testDifferenceOutput[T]}func TestDifference(t *testing.T) {        for i, tt := range []testDifference[intOrString] {            testDifference[int]{                input: testDifferenceInput[int]{                    []int{1, 2, 3, 3, 4},                    []int{1, 2, 5},                    []int{1, 3, 6},                },                output: []int{4, 5, 6},            },            testDifference[string]{                input: testDifferenceInput[string]{                    []string{"1", "2", "3", "3", "4"},                    []string{"1", "2", "5"},                    []string{"1", "3", "6"},                },                output: []string{"4", "5", "6"},            },        } 
查看完整描述

2 回答

?
茅侃侃

TA贡献1842条经验 获得超21个赞

如果您因为它的通用标题(不是双关语)而遇到这个问答,这里有一个关于工会的快速入门:

  1. 可用于指定接口约束的类型集。泛型类型参数T将被限制为联合中的类型

  2. 只能在接口约束中使用。如果一个接口包含一个联合(带有一个或多个术语),那么它就是一个接口约束。

  3. 可以包括近似元素~

例如:

type intOrString interface {

    int | string

}


func Foo[T intOrString](x T) {

    // x can be int or string

}

现在谈谈OP的问题,还有更多细节:

您不能将接口约束用作类型

通过包含类型集,intOrString成为接口约束,并且明确不支持将其用作类型。允许约束作为普通接口类型

这是我们现在不建议的功能,但可以考虑用于该语言的更高版本。

所以首先要做的是intOrString用作实际约束,因此在类型参数列表中使用它。下面我替换comparableintOrString

type testDifferenceInput[T intOrString] [][]T

type testDifferenceOutput[T intOrString] []T

type testDifference[T intOrString] struct {

    input testDifferenceInput[T]

    output testDifferenceOutput[T]

}

这也意味着您不能使用约束将具体类型实例化为测试切片:

// bad: using intOrString to instantiate a parametrized type[]testDifference[intOrString]

通用容器不能容纳不同类型的项目

您遇到的第二个问题是测试切片包含两个不相关类型的结构。一个是testDifference[int],一个是testDifference[string]。即使类型testDifference本身使用联合约束进行参数化,它的具体实例也不是相同的类型。另请参阅以获取更多详细信息。

如果您需要一个包含不同类型的切片,您唯一的选择是[]interface{}(或[]any) ...或者,您只需将切片分开:

ttInts := []testDifference[int]{ testDifference[int]{...}, /* etc. */ }
ttStrs := []testDifference[string]{ testDifference[string]{...}, /* etc. */ }

允许对联合约束的操作

只有类型集中所有类型都支持的操作。基于类型集的操作

规则是泛型函数可以以参数约束的类型集的每个成员所允许的任何方式使用其类型为类型参数的值。

如果有类似 的约束,在或int | string上允许的操作是什么?简而言之:intstring

  • 变量声明 ( var foo T)

  • 转换和断言T(x),并x.(T)在适当的时候

  • 比较 ( ==!=)

  • 排序 ( <<=,>>=)

  • +操作员

所以你可以有一个intOrString约束,但使用它的功能,包括你的 func Difference,仅限于这些操作。例如:

type intOrString interface {

    int | string

}


func beforeIntOrString[T intOrString](a, b T) bool {

    return a < b

}


func sumIntOrString[T intOrString](a, b T) T {

    return a + b

}


func main() {

    fmt.Println(beforeIntOrString("foo", "bar")) // false

    fmt.Println(beforeIntOrString(4, 5)) // true


    fmt.Println(sumIntOrString("foo", "bar")) // foobar

    fmt.Println(sumIntOrString(10, 5)) // 15

}


查看完整回答
反对 回复 2022-10-10
?
人到中年有点甜

TA贡献1895条经验 获得超7个赞

我已经通过gotip传递了您的代码,该代码使用了更完善的提案实现,并且它没有抱怨该部分代码,所以我认为问题出在 go2go 初始实现上。

请注意,您的实现将不起作用,因为您绝对可以在类型断言表达式中使用参数接口,但是您不能像在testDifference[intOrString]


查看完整回答
反对 回复 2022-10-10
  • 2 回答
  • 0 关注
  • 80 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信