scala – 逆变型的方法继承
我定义了两个类型类:
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) <= 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 [Y< ;: X](x:Y,y:Y):Y不能继承def sup [X](x:X,y:X):X.编译器抱怨类型签名不匹配.但是前者(具有现场方差注释)强加了比后者签名更强的类型限制.为什么前者不能继承后者呢?如何绕过TotalOrder [-X]的逆变类型限制(从语义上讲,总顺序是逆变的)? 解决方法
这在语义上不正确.应该从协变和逆变的定义中明确,但我会试着给出一个例子:
假设我们有实体的层次结构: class Shape(s:Float) class Circle(r:Float) extends Shape(Math.PI.toFloat * r * r) 我们假设您可以创建逆变订单,就像您尝试的那样: trait CircleOrder extends TotalOrder[Circle] { // compare by r } trait ShapeOrder extends TotalOrder[Shape] { // compare by s } 根据变形的定义,如Shape<:Circle, 假设我们有以CircleOrder为参数的客户端 def clientMethod(circleOrder:TotalOrder[Circle]) = { val maxCircle = circleOrder.max(???,???) // expected to return Circle maxCircle.r // accessing field that is present only in circle } 然后,根据继承的定义,应该可以通过 clientMethod(new ShapeOrder {/*...*/}) 显然它不会起作用,因为客户仍然希望命令返回Circles,而不是Shapes. 我认为在你的情况下,最合理的方法将使用常规泛型. 更新 这是你如何确保类型安全,但它有点难看. trait WeakOrder[-X] { def cmp(x: X,y: X): Int def max[T](x: X with T,y: X with T): T = if (cmp(x,y) >= 0) x else y def min[T](x: X with T,y) <= 0) x else y } trait Lattice[X] { def sup[T](x: X with T,y: X with T): T def inf[T](x: X with T,y: X with T): T } trait TotalOrder[-X] extends Lattice[X] with WeakOrder[X] { def sup[T](x: X with T,y: X with T): T = max(x,y) def inf[T](x: X with T,y: X with T): T = min(x,y) } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |