2

这个 Scala 教程让我很困惑;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呢?我问,因为显然上面的代码不会编译 - 为什么必须使用“自类型引用”?(见教程

4

2 回答 2

7

你颠倒了 的意思<:。ANode可分配给 a NodeIntf,即:

val x: NodeIntf = y: Node

现在,在下面你说Node = NodeIntfand NodeIntf = NodeImpl,这是不正确的。Node是 的任意子类型NodeIntf,并且NodeImpl是 的特定子类型NodeIntf

is aNodeis aNodeIntfNodeImplis a而言NodeIntf,但这对它们之间的关系没有任何意义——您不妨说 bothNodeNodeImpl都是 的子类型Any

于 2013-02-15T13:12:53.173 回答
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

在您的代码中,您尝试传递一个 to 的实例NodeImplnewEdge它需要一个Node. 您是对的,它NodeImpl是 的子类型NodeIntf,但是, 的实现Graph可能会决定Node通过将其绑定到 的子类型来进一步限制NodeImpl,这会使您的调用newEdge非法。

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

type Node = NodeIntf

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

于 2013-02-15T13:20:53.193 回答