Scala之旅-内部类

Scala之旅-内部类

内部类(Inner Classes)

在Scala中一个类可以作为另一个类的成员。在类Java语言中,内部类是封闭类的成员,与此相反,在Scala中,内部类受到外部对象的约束。假设我们想让编译器在编译时阻止我们混淆哪个nodes属于什么graph。路径依赖类型(Path-dependent types)提供了一种解决方案。

为了阐明这种区别,我们快速实现一个graph数据类型:

class Graph {
  class Node {
    var connectedNodes: List[Node] = Nil
    def connectTo(node: Node) {
      if (connectedNodes.find(node.equals).isEmpty) {
        connectedNodes = node :: connectedNodes
      }
    }
  }
  var nodes: List[Node] = Nil
  def newNode: Node = {
    val res = new Node
    nodes = res :: nodes
    res
  }
}

这个程序用一个列表nodes(List[Node])表示一个graph。每个node具有一个它所连接的其它nodes的列表(connectedNodes)。由于类Node嵌套在类Graph中,所以它是一个路径依赖的类型。因此,所有在connectedNodes中的nodes必须使用来自同一个Graph实例的newNode来创建。

val graph1: Graph = new Graph
val node1: graph1.Node = graph1.newNode
val node2: graph1.Node = graph1.newNode
val node3: graph1.Node = graph1.newNode
node1.connectTo(node2)
node3.connectTo(node1)

为了清晰,我们将node1,node2和node3的类型显式声明为graph1.Node,不过编译器是可以推断出来的。这是因为当我们调用graph1.newNode(newNode调用了new Node)时,这个方法使用的Node实例是特定于实例graph1的。

如果我们有两个graphs,Scala的类型系统不允许我们将定义在一个graph的nodes与另一个graph的nodes混合在一起,这是因为其它graph的nodes具有不同的类型。下面是一个非法的程序:

val graph1: Graph = new Graph
val node1: graph1.Node = graph1.newNode
val node2: graph1.Node = graph1.newNode
node1.connectTo(node2)      // legal
val graph2: Graph = new Graph
val node3: graph2.Node = graph2.newNode
node1.connectTo(node3)      // illegal!

类型graph1.Node与类型graph2.Node是不同的。在Java中,上面程序的最后一行是正确的。对于两个graphs,Java会分配相同的类型Graph.Node;也就是说Node会以类Graph为前缀。在Scala中,也可以表达这种类型,记作Graph#Node。如果我们想连接不同graphs的nodes,需要按如下方式改变graph最初的定义:

class Graph {
  class Node {
    var connectedNodes: List[Graph#Node] = Nil
    def connectTo(node: Graph#Node) {
      if (connectedNodes.find(node.equals).isEmpty) {
        connectedNodes = node :: connectedNodes
      }
    }
  }
  var nodes: List[Node] = Nil
  def newNode: Node = {
    val res = new Node
    nodes = res :: nodes
    res
  }
}

注意这个程序不允许我们将一个node依附在两个不同的graphs之上。如果想将这个限制也移除掉,需要将变量nodes的类型修改为Graph#Node。

参考资料

本文译自Tour Of Scala – Inner Classes

上一篇:Scala之旅-类型下界

下一篇:Scala之旅-抽象类型

发表评论

电子邮件地址不会被公开。 必填项已用*标注