2012-02-08 97 views
8

我想圍繞抽象和明確的自我類型在斯卡拉我的頭。 讓我們考慮這個例子: 我想創建一個可擴展的樹這麼簡單一個基地:斯卡拉自我類型和this.type在集合問題

trait Tree { 
    def children: Iterable[Tree] 
    def descendants: Iterable[Tree] = { val dv = children.view; dv ++ (dv.flatMap { _.children }) } 
} 

不過,我希望能夠用一些方法來擴展的樹節點,並使用這些方法,如:tree.children foreach { _.newMethod() }

爲此,我已經試過:

A. this.type:FAIL

trait Tree { 
    def children: Iterable[this.type] 
    def descendants: Iterable[this.type] = { 
     val dv = children.view 
     // FAIL: type mismatch; found : scala.collection.IterableView[com.abovobo.data.Tree,Iterable[_]] required: Iterable[Tree.this.type] 
     // dv ++ (dv.flatMap { _.children }) 
     // OK: 
     dv.++[this.type, Iterable[this.type]](dv.flatMap[this.type, Iterable[this.type]]{ _.children }) 
    } 
} 

工作變體非常笨拙。

B.抽象類型:失敗

trait Tree { 
    type Node <: Tree 

    def children: Iterable[Node] 
    def descendants: Iterable[Node] = { 
     val dv = children.view 
     // FAIL: type mismatch; found : scala.collection.IterableView[com.abovobo.data.Tree#Node,Iterable[_]] required: Iterable[Tree.this.Node] 
     dv ++ (dv.flatMap { _.children }) 
    } 
} 

完全不因道路特定類型不匹配我的理解工作。

C.類型PARAMS(仿製藥):OK

trait Tree[+Node <: Tree[Node]] { 

    def children: Iterable[Node] 

    def descendants: Iterable[Node] = { 
     val dv = children.view 
     dv ++ (dv.flatMap { _.children }) 
    } 
} 

工程確定,但不是那麼好派生類中維護。

任何想法如何使第一個兩個變種沒有噸代碼工作?

另外,有了這個類型,我遇到了執行問題。

trait BiDTree extends Tree { 
    def parent: Option[this.type] 
} 

// how to accept this param? Option[TreeImpl] doesn't work. 
class TreeImpl(val parent: Option[???]) extends BiDTree { 
    // ... 
} 

謝謝!

+3

啊是的。 「Scala沒有MyType」問題。 – 2012-02-08 19:11:14

+0

正如你所看到的,我在SO中查看了這個,並嘗試了提議的變體。它適用於非常簡單的構造(比如Martin的論文中的'c.incr()。decr()'示例),但對於集合則不適用。 – tuxSlayer 2012-02-08 19:18:26

+1

是的。得到了點爲什麼看完你的討論後在這裏http://www.scala-lang.org/node/6649, 謝謝 – tuxSlayer 2012-02-08 22:26:30

回答

1

在最後我用什麼在這次討論中提出http://www.scala-lang.org/node/6649入駐:

trait Tree[+Node <: Tree[Node]] { 
    this: Node => 

    def children: Iterable[Node] 

    def descendants: Iterable[Node] = { 
     val dv = children.view 
     dv ++ (dv.flatMap { _.children }) 
    } 
} 

即變體(C)但具有明確的自我類型。這給了在其他方法中使用this的機會(比如方法find(path: String): Option[Node])。

5

沒有真正理解這個問題是你有什麼用(C),你可以嘗試(B)的變體:

trait Tree { 
    type Node <: Tree 

    def children: Iterable[Tree#Node] 
    def descendants: Iterable[Tree#Node] = { 
     val dv = children.view 
     dv ++ (dv.flatMap { _.children }) 
    } 
} 

避免了你的路徑特定類型的問題。 順便說一句,你真的應該看看http://www.assembla.com/spaces/scala-graph/wiki

+1

哦,謝謝,錯過了這種類型選擇符表示法。 至於(C) - 我將這些類型的參數添加到所有的孩子類。這不是很方便。 – tuxSlayer 2012-02-08 20:09:03