类型参数中的 Scala 特征 'this.type'



看看这两个简单的特征:

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 不同意我的观点。

附言至少它想知道关于Scala的理论问题,而不是广泛的实际用途。

它的子级与当前特征混合的类具有相同的类型

不。这是一个常见的误解。this.type是单例类型的this;即只有两个值是thisnull的类型。TreeNode2实例的所有子实例必须是同一实例。

若要回答问题的另一部分,一种选择是将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模式(,但这是否适合您取决于它们的使用方式。

最新更新