1. 程式人生 > >Scala之旅(TOUR OF SCALA)——內部類(INNER CLASSES)

Scala之旅(TOUR OF SCALA)——內部類(INNER CLASSES)

在 Scala 中,讓類中有其它類作為成員是可能的。與類 Java 的語言內部類作為封閉類的成員相反,,在 Scala 中內部類是被繫結到外部物件上的。假設編譯器在編譯時想阻止我混合哪些結點屬於哪些類。路徑依賴型別提供了一個解決方案。

為了演示不同, 我們迅速實現一個圖的資料型別:

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 } }

這個程式代表了一個擁有列表結點(List[Node])的圖。每個結點

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)
node2.connectTo(node3)

我們明確地聲明瞭 node1node2node3 的型別為 graph1.Node ,但是實際上編譯器可以推斷出它。這是因為當我們呼叫 graph1.newNode 時呼叫了 new Node ,這個方法使用了特定例項 garph1Node 的例項。

如果我們有兩個圖的例項,Scala 的型別系統不會允許我們把一個例項圖中的定義的結點混合到另一個例項圖中定義的結點中。因為另一個例項圖中的結點型別是另一種型別。這裡有一個錯誤的程式例子:

val graph1: Graph = new Graph
val node1: graph1.Node = graph1.newNode
val
node2: graph1.Node = graph1.newNode node1.connectTo(node2) // 合法 val graph2: Graph = new Graph val node3: graph2.Node = graph2.newNode node1.connectTo(node3) // 非法

graph1.Nodegrpah2.Node 型別是不同的。在 Java 中上面的例子中的最後一行是對的。圖中結點的型別都是相同的 Graph.Node 型別。在 Scala 中像這樣的型別被表示為 Graph#Node 。如果我們想讓不同的圖中的結點一起使用,可以改變在圖中的定義像下面的例子進行實現:

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
    }
}

注意:內部類不允許我們將兩個圖中的結點一起使用,如果我們想解除這個限制,我們需要改變結點變數的型別為 Grpah#Node