类型参数中的 Scala trait `this.type`

Scala trait `this.type` in type parameter

看看这两个简单的特征:

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

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

理论上TreeNode2TreeNode1的特例:

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

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

我该如何解决这种情况?或者 Scala 不提供这种使用不当的机制?


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

我有另一个特征需要混合 TreeNode1。我还有一些 class 将 TreeNode1 与另一种 children 类型混合。但我也有几个 classes,它们具有相同的类型:

class SomeTreeNode extends TreeNode1[SomeTreeNode]

所以用TreeNode2会更漂亮:

class SomeTreeNode extends TreeNode2

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

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

its children have the same type as the class the current trait is mixed

没有。这是一个常见的误解。 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 模式),但这是否适合您取决于它们的使用方式。