【问题标题】:Recursive type constraint using a defined type rather than a type literal?使用定义类型而不是类型文字的递归类型约束?
【发布时间】:2021-02-04 15:27:17
【问题描述】:

在目前的草案中,在 Go2 泛型中,我可以使用接口对泛型类型指定类型约束。

import "fmt"

type Stringer interface {
    String() string
}

func Print[T Stringer](value T) {
    fmt.Println(value.String())
}

这样,我可以指定类型必须实现一个方法。但是,我没有看到任何强制实现方法的方法,因为它本身具有泛型类型的参数。

type Lesser interface {
    Less(rhs Lesser) bool
}

type Int int

func (lhs Int) Less(rhs Int) bool {
    return lhs < rhs
}

func IsLess[T Lesser](lhs, rhs T) bool {
    return lhs.Less(rhs)
}

func main() {
    IsLess[Int](Int(10), Int(20))
}

退出

Int does not satisfy Lesser: wrong method signature
    got  func (Int).Less(rhs Int) bool
    want func (Lesser).Less(rhs Lesser) bool

带有合同的原始草案将使这成为可能,但新草案却不行。

也可以通过以下方式完成,但这会让您一遍又一遍地重复相同的约束,制动 DRY(而 DRY 代码是泛型的目的)。如果所需的接口有多个方法,也会使代码更加笨拙。

func IsLess[T interface { Less(T) bool }](lhs, rhs, T) bool {
    return lhs.Less(rhs)
}

有没有办法在新草案中使用预定义的界面来做到这一点?

【问题讨论】:

  • 嗯,首先,接口中的函数有签名Less(rhs Lesser) bool和你的实现有签名Less(rhs Int) bool,不一样。
  • 当然可以,但是如何为func (lhs T) Less(rhs T) bool {} 创建一个通用约束?
  • 草稿中有一段关于此的内容:go.googlesource.com/proposal/+/refs/heads/master/design/… 看来没有简单的方法可以做到这一点。
  • @torek,考虑使用具有多种方法的接口来执行此操作。结果将无法读取。
  • 老实说,我今天刚刚查看了 Go 中仿制药的情况,我真的很失望,合同被削减了。我发现合同真的很棒。并且可能更干燥,因为您只需定义整个文件/包的通用类型。此外,当前草案中的一些内容允许您对具有 > 和

标签: go generics interface


【解决方案1】:

定义接口类型Lesser和函数Isless如下:

type Lesser[T any] interface {
    Less(T) bool
}

func IsLess[T Lesser[T]](lhs, rhs T) bool {
    return lhs.Less(rhs)
}

然后,以下代码顺利编译:

type Apple int

func (lhs Apple) Less(rhs Apple) bool {
    return lhs < rhs
}

type Orange int

func (lhs Orange) Less(rhs Orange) bool {
    return lhs < rhs
}

func main() {
    fmt.Println(IsLess(Apple(10), Apple(20)))   // true
    fmt.Println(IsLess(Orange(30), Orange(15))) // false

    // fmt.Println(IsLess(10, 30))
    // compilation error: int does not satisfy Lesser[T] (missing method Less)

    // fmt.Println(IsLess(Apple(20), Orange(30)))
    // compilation error: type Orange of Orange(30) does not match inferred type Apple for T
}

(Playground)


约束T Lesser[T] 可以读作

具有Less(T) bool 方法的任何类型T

我的两种自定义类型,

  • Apple 及其 Less(Apple) bool 方法,以及
  • Orange 及其 Less(Orange) bool 方法,

满足这个要求。

有关信息,Java 泛型允许通过称为recursive type bound 的类似技巧。有关此主题的更多信息,请参阅 Josh Bloch 的Effective Java,第 3 版中的第 30 项(尤其是 p137-8)。


完全披露:当我在Gophers Slack 上遇到Vasko Zdravevski's solutiona similar problem 时,我想起了这个悬而未决的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-21
    • 1970-01-01
    • 2013-11-05
    • 2023-03-31
    • 1970-01-01
    • 2021-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多