类型参数

时间:2018-05-29 20:37:46

标签: scala inheritance traits

看看这两个简单的特征:

trait TreeNode1[S] {
    def subNodes: List[S]
}
trait TreeNode2 {
    def subNodes: List[this.type]
}

(不是最佳命名,重命名为简短。)
TreeNode1定义了一个树节点及其子节点访问,指向其类型S TreeNode2定义相同,但它的子类与当前特征混合的类具有相同的类型(换句话说,树节点具有统一的子节点)。

理论上 TreeNode2TreeNode1 的特例:

trait TreeNode2 extends TreeNode1[this.type] {...}

但是 Scala不会使用这样的扩展来编译TreeNode2 ,因为this.type不能以这种方式使用,尽管它在运行时没有任何不一致。

我怎样才能解决这种情况?或者Scala不提供这种使用不当的机制?

我需要这种结构的原因如下:

我有另一个需要TreeNode1混入的特性。我还有一些类将TreeNode1与另一个子类型混合在一起。但我也有几个类型与它们相同的类:

class SomeTreeNode extends TreeNode1[SomeTreeNode]

如果我使用TreeNode2,它看起来会更漂亮:

class SomeTreeNode extends TreeNode2

实现相同的逻辑。但是使用TreeNode2应该是TreeNode1的情况,实际上是这样,但Scala不同意我的看法。

P.S。至少它想知道关于Scala的理论问题,而不是广泛的实际应用。

1 个答案:

答案 0 :(得分:1)

  

其子项与当前特征混合的类具有相同的类型

没有。这是一种常见的误解。 this.typethis的单例类型;即the type whose only two values are this and nullTreeNode2实例的所有子项必须是同一个实例。

要回答问题的其他部分,一个选项是使S成为类型成员而不是类型参数:

trait TreeNode1 {
    type S
    def subNodes: List[S]
}
object TreeNode1 {
    // use TreeNode1.Aux[S] where you had TreeNode1[S] originally
    type Aux[T] = TreeNode1 { type S = T }
}

trait TreeNode2 {
    type S = this.type // not really what you want
    def subNodes: List[this.type]
}

(所谓的Aux模式),但这是否适合你取决于它们的使用方式。