我正在使用 Scala 开发一个小型渲染引擎来学习该语言。引擎的架构强烈基于特征,因此我可以根据需要添加和删除管道的一部分。一些特征是:
(更新:更正了一些类型信息)
trait Composable { val parent:DisplayObject with Composite = null }
trait Composite extends Composable { val children:ArrayBuffer[DisplayObject with Composable] = ArrayBuffer() }
trait Position { var x = 0.0d; var y = 0.0d }
...
DisplayObject
是一个用于组成这些特征的空类。
我的管道中的一个步骤是展平每个对象的层次结构。我的第一个镜头是:(更新:我添加了身体)
def flatten(root:DisplayObject with Composite) : ArrayBuffer[DisplayObject] =
{
def traverse(composite:Composite, acc:ArrayBuffer[DisplayObject])
{
acc += composite
for(composable <- composite.children)
{
composable match {
case com:Composite => traverse(com, acc)
case _ => acc += composable
}
}
}
val flat = new ArrayBuffer[DisplayObject]
traverse(root, flat)
flat
}
}
这很好,但是,当我调用这个函数时,我丢失了很多类型信息:
val root = new DisplayObject with Position with Composite
root.children += new DisplayObject with Composable with Position
val list = flatten(root)
的类型list
是现在List[DisplayObject]
。我丢失了位置信息。所以我考虑将泛型添加到组合中:(更新:添加正文)
def genericFlatten[T](root:T with Composite) : ArrayBuffer[T] =
{
def traverse(composite:T with Composite, acc:ArrayBuffer[T])
{
acc += composite
for(composable <- composite.children)
{
composable match {
case com:T with Composite => traverse(com, acc)
case composable:T with Composable => acc += composable
}
}
}
val flat = new ArrayBuffer[T]
traverse(root, flat)
flat
}
但是,调用它会给我一个奇怪的结果:返回列表的类型是 now List[DisplayObject with Position with Composite]
,这是错误的,因为树的某些子节点(叶子)将不具有 Composite 特征。我期待类型 T 被推断为DisplayObject with Position
. 不?