我定义了两个类型类:
trait WeakOrder[-X] { self =>
def cmp(x: X, y: X): Int
def max[Y <: X](x: Y, y: Y): Y = if (cmp(x, y) >= 0) x else y
def min[Y <: X](x: Y, y: Y): Y = if (cmp(x, y) <= 0) x else y
}
trait Lattice[X] { self =>
def sup(x: X, y: X): X
def inf(x: X, y: X): X
}
我想做以下事情:
trait TotalOrder[-X] extends Lattice[X] with WeakOrder[X] { self =>
def sup(x: X, y: X): X = max(x, y)
def inf(x: X, y: X): X = min(x, y)
}
但这是不可能的,因为逆变类型 X
出现在协变位置( sup
和 inf
的返回值) .
但是,在语义上这是正确的:带有类型签名的 max
和 min
max[Y <: X](x: Y, y: Y): Y
编码 max
/ min
的返回值必须是两个参数之一的事实 .
我试着做以下事情:
trait TotalOrder[-X] extends Lattice[X] with WeakOrder[X] { self =>
def sup[Y <: X](x: Y, y: Y): Y = max(x, y)
def inf[Y <: X](x: Y, y: Y): Y = min(x, y)
}
但是,方法 def sup[Y <: X](x: Y, y: Y): Y
无法继承 def sup[X](x: X, y: X): X
. 编译器抱怨类型签名不匹配 . 但是前者(具有现场方差注释)强加了比后者签名更强的类型限制 . 为什么前者不能继承后者呢?如何绕过 TotalOrder[-X]
的逆变类型限制(从语义上讲,总顺序是逆变的)?
1 回答
这在语义上不正确 . 应该从协变和逆变的定义中明确,但我会试着给出一个例子:
假设我们有实体的层次结构:
我们假设您可以创建逆变订单,就像您尝试的那样:
根据矛盾的定义,如
Shape <: Circle
,CircleOrder <: ShapeOrder
(CircleOrder是ShapeOrder的超类型)假设我们有客户端将CircleOrder作为参数并使用它来比较圈子:
然后,根据继承的定义,应该可以传递ShapeOrder而不是CircleOrder(记住,ShapeOrder是子类型):
显然它不会起作用,因为客户仍然希望命令返回Circles,而不是Shapes .
我认为在你的情况下,最合理的方法将使用常规泛型 .
更新
这是你如何确保类型安全,但它有点难看 .