首页 文章

逆变型的方法继承

提问于
浏览
5

我定义了两个类型类:

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 出现在协变位置( supinf 的返回值) .

但是,在语义上这是正确的:带有类型签名的 maxmin 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 回答

  • 0

    这在语义上不正确 . 应该从协变和逆变的定义中明确,但我会试着给出一个例子:

    假设我们有实体的层次结构:

    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 <: CircleCircleOrder <: ShapeOrder (CircleOrder是ShapeOrder的超类型)

    假设我们有客户端将CircleOrder作为参数并使用它来比较圈子:

    def clientMethod(circleOrder:TotalOrder[Circle]) = {
      val maxCircle = circleOrder.max(???, ???) // expected to return Circle
      maxCircle.r // accessing field that is present only in circle
    }
    

    然后,根据继承的定义,应该可以传递ShapeOrder而不是CircleOrder(记住,ShapeOrder是子类型):

    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: X with T): T =
            if (cmp(x, 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)
        }
    

相关问题