我有3个特征
trait A
trait B
trait AB extends A with B
和方法
def collect[E: Manifest](list: List[Any]) =
list flatMap {
case record: E => Some(record)
case _ => None
}
对于给定的列表
val list = new A {} :: new A {} :: new A with B {} :: new AB {} :: Nil
我使用不同类型
调用了collect
collect[A with B](list) // collect all elements from the list
collect[AB](list) // collect only the last element
有人可以解释A with B
和AB
类型的行为差异吗?
答案 0 :(得分:5)
非常不直观但它符合规范。首先,引用Manifest docs(强调我的):
Manifest [T]是类型T的不透明描述符。它支持的用途是访问类型的擦除
所以在collect[A with B]
我们匹配A with B
的删除。那是什么?如果我们查看规范的Type erasure部分,我们会看到:
复合类型 T1 with ... with Tn 的擦除是 T1,...,Tn 的交叉支配者的擦除
和交叉点支配者被定义为(再次强调我的)
类型列表 T1,...,Tn 的交集支配者计算如下。设 Ti1,...,Tim 是类型 Ti 的子序列,它们不是某些其他类型 Tj 的超类型。如果此子序列包含类型指示符 Tc ,它引用的类不是特征,则交集支配者是 Tc 。否则,交叉点支配者子序列的第一个元素, Ti1
在我们的例子中,子序列是A,B
,因为它们没有任何子类型关系,因此A with B
的删除是A
,所以在collect[A with B]
我们实际上是匹配A
。
您可以通过查看collect[B with A]
的输出和/或向new B {}
添加list
来轻松查看此行为。