2016-12-21 5 views
6

У меня 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 типов?

ответ

5

Это очень неинтуитивный, но он соответствует спецификации. Во-первых, со ссылкой на от Manifest docs (курсив):

манифеста [Т] является непрозрачным дескриптор типа T. поддерживаемых использования, чтобы дать доступ к стиранием типа

Итак, в collect[A with B] мы сопоставляем erasure of A with B. И что это? если мы посмотрим на Type erasure части спецификации, мы читаем:

Стирание составного типа T1 с ... с Тп является стирание пересечения доминатором T1, ..., Тп

и пересечения Dominator определяется как (опять же, курсив мой)

пересечение доминатором список типов 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.