我试图理解 scala 中抽象和显式的自我类型。
让我们考虑这个例子:
我想为可扩展树创建一个基础,就像这样简单:
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: 失败
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. 抽象类型:FAIL
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. 类型参数(泛型):确定
trait Tree[+Node <: Tree[Node]] {
def children: Iterable[Node]
def descendants: Iterable[Node] = {
val dv = children.view
dv ++ (dv.flatMap { _.children })
}
}
工作正常,但在派生类中维护不太好。
有什么想法可以让前两个变体在没有大量代码的情况下工作吗?
另外,对于 this.type 我遇到了实施问题。
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 {
// ...
}
Thanks!