复合类型的意外行为

时间:2016-12-21 10:32:45

标签: scala types pattern-matching type-erasure

我有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 BAB类型的行为差异吗?

1 个答案:

答案 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来轻松查看此行为。