9

我正试图围绕 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. 类型参数(泛型):OK

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 {
  // ...
}

谢谢!

4

2 回答 2

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

于 2012-02-08T19:58:11.900 回答
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(例如 method find(path: String): Option[Node])。

于 2012-02-09T13:15:57.640 回答