收集问题中的Scala自我类型和this.type

tux*_*yer 9 scala self-type abstract-type

我试图在scala中围绕抽象和显式自我类型.让我们考虑这个例子:我想为可扩展树创建一个简单的基础:

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

但是,我希望能够使用某些方法扩展树节点并使用以下方法: 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 })
    }
}
Run Code Online (Sandbox Code Playgroud)

工作变体非常笨拙.

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 })
    }
}
Run Code Online (Sandbox Code Playgroud)

根据我的理解,由于路径特定类型不匹配,根本不起作用.

C.类型params(泛型):好的

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

    def children: Iterable[Node]

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

工作正常,但在派生类中维护不太好.

任何想法如何使前两个变体工作没有大量的代码?

另外,使用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 {
  // ...
}
Run Code Online (Sandbox Code Playgroud)

谢谢!

Jan*_*rst 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 })
    }
}
Run Code Online (Sandbox Code Playgroud)

这避免了您的路径特定类型问题.顺便说一下,你应该看看http://www.assembla.com/spaces/scala-graph/wiki


tux*_*yer 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 })
    }
}  
Run Code Online (Sandbox Code Playgroud)

即变体(C),但具有明确的自我类型。this这提供了在其他方法(例如 method )中使用的机会find(path: String): Option[Node]