Scala抽象类型和多态性

时间:2013-02-15 12:30:15

标签: scala

This Scala tutorial让我感到困惑; Node抽象类型似乎不遵循传统的多态性规则......

type Node <: NodeIntf                // NodeIntf is assignable to Node.
abstract class NodeIntf {
  def connectWith(node: Node): Edge
}
class NodeImpl extends NodeIntf {
  def connectWith(node: Node): Edge = {
    val edge = newEdge(this, node)   // NodeImpl (this) is assignable to NodeIntf.
    edges = edge :: edges
    edge
  }
}
protected def newEdge(from: Node, to: Node): Edge

如果Node = NodeIntfNodeIntf = NodeImpl,我们为什么不能Node = NodeImpl?我问,因为显然上面的代码不会编译 - 为什么必须使用'自键型引用'? (see tutorial

2 个答案:

答案 0 :(得分:7)

你颠倒了<:的含义。 Node可分配给NodeIntf,即:

val x: NodeIntf = y: Node

现在,在下面你说Node = NodeIntfNodeIntf = NodeImpl,这不是真的。 NodeNodeIntf任意子类型,NodeImplNodeIntf的特定子类型。

而言,NodeNodeIntf,而NodeImplNodeIntf,但对此没有意义他们之间的关系 - 您可能也说NodeNodeImpl都是Any的子类型。

答案 1 :(得分:3)

首先,这是一个代码的最小,自包含版本:

abstract class Graph {
  type Node <: NodeIntf

  case class Edge(s: Node, d: Node)

  abstract class NodeIntf {
    def connectWith(node: Node): Edge
  }

  class NodeImpl extends NodeIntf {
    def connectWith(node: Node): Edge = {
      val edge = newEdge(this, node)
      edge
    }
  }

  def newEdge(from: Node, to: Node): Edge = Edge(from, to)
}

如果您尝试编译它,您将获得

found   : NodeImpl.this.type (with underlying type Graph.this.NodeImpl)
required: Graph.this.Node
    val edge = newEdge(this, node)
                       ^

错误消息的原因是Node抽象类型。它有上限NodeIntf,但它仍然是抽象的。也就是说,抽象Graph的实现可以自由地设置/绑定Node NodeIntf的任何子类型。

在您的代码中,您尝试将NodeImpl的实例传递给newEdge,该实例需要Node。你是对的NodeImpl是[{1}}的子类型,但NodeIntf的实现可能决定通过将Graph绑定到Node的子类型来进一步限制NodeImpl 1}},这会使您对newEdge的调用非法。

如果您已绑定Node,例如,将其设为NodeIntf的类型别名,

type Node = NodeIntf

然后上面的代码编译,因为Graph的后续实现不再绑定Node