使用定义的类型而不是类型文字的递归类型约束?
Recursive type constraint using a defined type rather than a type literal?
在 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)
}
有没有办法在新草案中使用预定义的接口来做到这一点?
定义接口类型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
}
约束 T Lesser[T]
可以读作
any type T
that has a Less(T) bool
method.
我的两种自定义类型,
Apple
及其 Less(Apple) bool
方法,以及
Orange
及其 Less(Orange) bool
方法,
满足这个要求。
有关信息,Java 泛型允许通过称为 recursive type bound 的类似技巧。有关此主题的更多信息,请参阅 Josh Bloch 的 Effective Java,第 3 版中的第 30 条(尤其是第 137-8 页)。
完全披露:当我遇到 Vasko Zdravevski's solution to a similar problem on Gophers Slack 时,我想起了这个未回答的问题。
在 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)
}
有没有办法在新草案中使用预定义的接口来做到这一点?
定义接口类型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
}
约束 T Lesser[T]
可以读作
any type
T
that has aLess(T) bool
method.
我的两种自定义类型,
Apple
及其Less(Apple) bool
方法,以及Orange
及其Less(Orange) bool
方法,
满足这个要求。
有关信息,Java 泛型允许通过称为 recursive type bound 的类似技巧。有关此主题的更多信息,请参阅 Josh Bloch 的 Effective Java,第 3 版中的第 30 条(尤其是第 137-8 页)。
完全披露:当我遇到 Vasko Zdravevski's solution to a similar problem on Gophers Slack 时,我想起了这个未回答的问题。