2014-11-14 5 views
12

TL; DR: Es scheint, dass Typ Parameter des Typs Aliase (z. B. type T[X<:Serializable]) ihre Einschränkungen nicht erzwingen, wenn als Variablen, Parameter und vielleicht andere Fälle verwiesen. Fallklassen erzwingen jedoch die Grenzen für ihre Parameter korrekt.Typ Alias-Parameter Grenzen nicht in allen Fällen erzwungen

Betrachten Sie einen Typalias, der eine Untermenge des generischen Typs darstellt. Zum Beispiel lassen Sie uns sagen, dass ich einen Typen für Listen von Serializable Dingen will:

scala> type SerializableList[T <: Serializable] = List[T] 
defined type alias SerializableList 

Jetzt sagen, dass ich eine Fall-Klasse mit einem Parameter dieser Dinge will:

scala> case class NetworkDataCC(things: SerializableList[_]) 
<console>:9: error: type arguments [_$1] do not conform to type SerializableList's type parameter bounds [T <: Serializable] 
    case class NetworkDataCC(things: SerializableList[_]) 

Nun, das doesn‘ t arbeiten. Scala (annoyingly) trägt nicht die Parametergrenzen mit der Art, aber es ist einfach zu beheben:

scala> case class NetworkDataCC(things: SerializableList[_ <: Serializable]) 
defined class NetworkDataCC 

In Ordnung. Sieht gut aus. Nun, was ist, wenn ich nur eine reguläre Klasse mit diesen Dingen möchte, aber ich vergesse wieder, die Typgrenzen explizit zu deklarieren. Ich erwarte einen Fehler:

scala> class NetworkData(val things: SerializableList[_]) 
defined class NetworkData 

Oh, warte. Kein Fehler ... huh.

Also, jetzt kann ich das tun?

scala> new NetworkData(List(1)) 
res3: NetworkData = [email protected] 

Nun, das scheint ziemlich kaputt. Der Fall Klasse, funktioniert natürlich (weil die Beschränkungen erklärt wurden):

scala> NetworkDataCC(List(1)) 
<console>:11: error: type mismatch; 
found : Int(1) 
required: Serializable 
       NetworkDataCC(List(1)) 

In meinem Projekt habe ich den Einsatz von Reflexion mache einige Metadaten über meine Klassen zu erzeugen. Die Metadaten für die Nicht-Fall-Klasse zeigen einen Mangel an Grenzen auf things:

scala> classOf[NetworkData].getDeclaredFields()(0).getGenericType 
res0: java.lang.reflect.Type = scala.collection.immutable.List<?> 

Während die Fallklasse ist richtig:

scala> classOf[NetworkDataCC].getDeclaredFields()(0).getGenericType 
res1: java.lang.reflect.Type = scala.collection.immutable.List<? extends scala.Serializable> 

ich in der scala alle Fehler finden nicht in der Lage war, Compiler-Bug-Tracker dafür. Missverstehe ich, wie diese Grenzen verwendet werden sollten?

+0

Interessante Frage. Ich vermute, dass der Compiler die von der Fallklasse erzeugte 'unapply'-Methode erstickt. Ich frage mich, warum die nicht-Fall-Klasse kompiliert. Aber das Problem scheint sich zu manifestieren, auch wenn wir keine neue Klasse deklarieren. Der Compiler akzeptiert happly "val y: SerializableList [_] = List (1)", was bereits ein ungültiger Ausdruck sein sollte. Vielleicht verursacht der Typ-Alias ​​das Problem? –

+0

Addendum (nicht-Fall-Klasse) zu meinem vorherigen Kommentar: Die Funktion 'def unapply (Wert: NetworkDataCC): Option [SerializableList [_]] = Einige (value.things)' kompiliert nicht, Drucken der Fehler: 'Typ Argumente [_ $ 1] stimmen nicht mit Typ-Parametergrenzen des Types SerializableList [T <: Serializable] 'überein. Der Compiler akzeptiert jedoch 'def unapply (value: NetworkDataCC): Option [SerializableList [_]] = Einige (value.things.asInstanceOf [SerializableList [Serializable]])', die auch mit 'NetworkDataCC (List (1)) 'übereinstimmen Zur Laufzeit gibt 'List (1)' zurück. –

+0

Ich bin sehr interessiert an diesem. Ich habe eine Prämie angefangen, hoffentlich kann jemand antworten. –

Antwort

4

Scala Strich ist nicht gleichbedeutend mit SerializableList[X forSome {type X}] standardmäßig:

scala> def aa(a: SerializableList[_]) = a 
aa: (a: SerializableList[_])List[Any] 

scala> def aa(a: SerializableList[X forSome {type X}]) = a 
<console>:11: error: type arguments [X forSome { type X }] do not conform to type SerializableList's type parameter bounds [T <: Serializable] 
    def aa(a: SerializableList[X forSome {type X}]) = a 
      ^
scala> class NetworkDataCC(things: SerializableList[X forSome {type X}]) 
<console>:11: error: type arguments [X forSome { type X }] do not conform to typ 
e SerializableList's type parameter bounds [T <: Serializable] 
    class NetworkDataCC(things: SerializableList[X forSome {type X}]) 

Es entspricht

scala> def aa(a: SerializableList[X] forSome {type X}) = a 
aa: (a: SerializableList[_])List[Any] 

So so "unbegrenzt" Verhalten in Ordnung ist. Überprüfen Sie diese Antwort: https://stackoverflow.com/a/15204140/1809978

Fallklassen scheinen zusätzliche Typeinschränkungen zu haben (aufgrund this bug, die unapply-Methode betrifft, automatisch für Fallklasse generiert).

Wenn Sie möchten, „unbegrenzt“ existenzielle Art bei Klasse haben, geben Sie einfach höhere Ordnung explizit eingeben:

scala> case class NetworkDataCC[SerializableList[_]](things: SerializableList[_]) 
warning: there were 2 feature warning(s); re-run with -feature for details 
defined class NetworkDataCC 

scala> NetworkDataCC(List(1)) 
res5: NetworkDataCC[List] = NetworkDataCC(List(1)) 

Oder auch:

scala> type SLL = SerializableList[_] 
defined type alias SLL 

scala> case class NetworkDataDD(things: SLL) 
defined class NetworkDataDD 

So dies auf jeden Fall ein Fehler ist in Bezug auf dass Sie es umgehen können mit semantisch äquivalenten Typ Alias ​​(siehe SI-8997)

Verwandte Themen