Scala: Typumwandlung ohne explizit bekannten Typparameter

Betrachten Sie das folgende Beispiel:

case class C[T](x:T) {
  def f(t:T) = println(t)
  type ValueType = T
}

val list = List(1 -> C(2), "hello" -> C("goodbye"))

for ((a,b) <- list) {
  b.f(a)
}

In diesem Beispiel weiß ich (Laufzeitgarantie), dass die Art vona wird ein @ seT, undb wird Typ @ habC[T] mit dem gleichenT. Natürlich kann der Compiler das nicht wissen, daher bekommen wir einen Tippfehler inb.f(a).

Um dem Compiler mitzuteilen, dass dieser Aufruf in Ordnung ist, müssen wir eine Typumwandlung à la @ durchführeb.f(a.asInstanceOf[T]). Unglücklicherweise,T ist hier nicht bekannt. Meine Frage lautet also: Wie schreibe ich @ neb.f(a) um diesen Code kompilieren zu lassen?

Ich suche nach einer Lösung, die keine komplexen Konstruktionen beinhaltet (um den Code lesbar zu halten) und die in dem Sinne "sauber" ist, dass wir uns nicht auf das Löschen von Code verlassen sollten, damit sie funktioniert (siehe den ersten Ansatz unten).

Ich habe einige Arbeitsansätze, aber ich finde sie aus verschiedenen Gründen unbefriedigend.

nsätze, die ich ausprobiert habe:
b.asInstanceOf[C[Any]].f(a)

Dies funktioniert und ist einigermaßen lesbar, basiert aber auf einer "Lüge".b ist nicht vom TypC[Any], und der einzige Grund, warum wir keinen Laufzeitfehler bekommen, ist, dass wir uns auf die Einschränkungen der JVM verlassen (Typ Erasure). Ich denke, es ist ein guter Stil, nur @ zu verwendx.asInstanceOf[X] wenn wir das wissenx ist wirklich vom TypX.

  b.f(a.asInstanceOf[b.ValueType])

Dies sollte nach meinem Verständnis des Typsystems funktionieren. Ich habe das Mitglied @ hinzugefüValueType zur KlasseC, um explizit auf den Typparameter @ verweisen zu könnT. Bei diesem Ansatz erhalten wir jedoch eine mysteriöse Fehlermeldung:

Error:(9, 22) type mismatch;
 found   : b.ValueType
    (which expands to)  _1
 required: _1
  b.f(a.asInstanceOf[b.ValueType])
                    ^

Warum? Es scheint sich zu beschweren, dass wir type @ erwart_1 aber bekam Typ_1! (Auch wenn dieser Ansatz funktioniert, ist er auf die Fälle beschränkt, in denen wir die Möglichkeit haben, ein Mitglied @ hinzuzufügeValueType zuC. WennC ist eine vorhandene Bibliotheksklasse, das können wir auch nicht.)

for ((a,b) <- list.asInstanceOf[List[(T,C[T]) forSome {type T}]]) {
  b.f(a)
}

Dieses funktioniert und ist semantisch korrekt (d. H. Wir "lügen" nicht beim Aufrufen vonasInstanceOf). Die Einschränkung ist, dass dies etwas unlesbar ist. Es ist auch etwas spezifisch für die gegenwärtige Situation: ifa,b nicht vom selben Iterator kommen, wo können wir dann diesen Typ Cast anwenden? (Dieser Code hat auch den Nebeneffekt, dass er für Intelli / J IDEA 2016.2 zu komplex ist, was ihn als Fehler im Editor hervorhebt.)

  val (a2,b2) = (a,b).asInstanceOf[(T,C[T]) forSome {type T}]
  b2.f(a2)

Ich hätte erwartet, dass dieser funktioniert, daa2,b2 sollte jetzt Typen habenT undC[T] für das gleiche existenzielleT. Aber wir bekommen einen Kompilierungsfehler:

Error:(10, 9) type mismatch;
 found   : a2.type (with underlying type Any)
 required: T
  b2.f(a2)
       ^

Warum? (Abgesehen davon hat der Ansatz den Nachteil, dass Laufzeitkosten (glaube ich) aufgrund der Erstellung und Zerstörung eines Paares anfallen.)

  b match {
    case b : C[t] => b.f(a.asInstanceOf[t])
  }

Das funktioniert. Das Einschließen des Codes mit einer Übereinstimmung macht den Code jedoch viel weniger lesbar. (Und es ist auch zu kompliziert für Intelli / J.)

Antworten auf die Frage(8)

Ihre Antwort auf die Frage