2016-12-21 21 views
6

Ich habe 3 ZügeUnerwartetes Verhalten mit Verbindungstypen

trait A 
    trait B 
    trait AB extends A with B 

und ein Verfahren

def collect[E: Manifest](list: List[Any]) = 
    list flatMap { 
     case record: E => Some(record) 
     case _   => None 
    } 

Für die gegebene Liste

val list = new A {} :: new A {} :: new A with B {} :: new AB {} :: Nil 

I collect aufgerufen mit verschiedenen Arten

collect[A with B](list) // collect all elements from the list 
collect[AB](list) // collect only the last element 

Kann jemand den Unterschied im Verhalten für A with B und AB Arten erklären?

Antwort

5

Es ist hochunintuitiv, aber es entspricht der Spezifikation. Zuerst wird unter Angabe von der Manifest docs (Hervorhebung von mir):

A Manifest [T] ist eine opake Deskriptor für Typ T. Sein Gebrauch unterstützt wird Zugriff auf die Löschungs geben des Typs

So in collect[A with B] passen wir die Löschung von A with B. Und was ist das? wenn wir an dem Type erasure Abschnitt der Spezifikation aussehen, lesen wir:

Das Löschen einer Verbindung Typen T1 mit ... mit Tn die Löschung der Kreuzung Beherrscher von T1, ..., Tn

und dem Schnittpunkt dominator wird als (wiederum emphasis Mine)

der Kreuzung dominator definierter Eine Liste der Typen T1, ..., Tn wird wie folgt berechnet. Lassen Sie Ti1, ..., Tim die Unterfolge der Typen Ti sein, die keine Supertypen eines anderen Typs sind Tj. Wenn diese Untersequenz einen Typbezeichner Tc enthält, der sich auf eine Klasse bezieht, die kein Merkmal ist, lautet der Überschneidungsdominator Tc. Ansonsten ist die Kreuzung Dominator das erste Element des Teilfolge, Ti1

In unserem Fall die Teilfolge ist A,B wie sie, keine Subtyping Beziehung haben und damit die Löschung von A with B ist A, so dass wir in collect[A with B] tatsächlich übereinstimmen A.

Sie können dieses Verhalten leicht sehen, indem Sie auf die Ausgabe von collect[B with A] schauen und/oder new B {} zu Ihrer list hinzufügen.