Scala Self Type и this.type в выпуске коллекций
Я пытаюсь обернуть голову вокруг абстрактных и явных типов себя в 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: 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. Абстрактные типы: 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. Тип params (дженерики): ОК
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 {
// ...
}
Спасибо!