13

Recentemente sono incappato in questo post, che "introduce" il metodo collect per le raccolte Scala. L'utilizzo è semplice:Utilizzo di collect su mappe in Scala

scala> val ints = List(1, "2", 3) collect { case i: Int => i } 
ints: List[Int] = List(1, 3) 

Ora mappe sono fondamentalmente liste di coppie chiave-valore, che sono rappresentati da tuple a Scala. Così si potrebbe desiderare di provare qualcosa di simile:

scala> val pairs = Map(1 -> "I", "II" -> 2) 
pairs: scala.collection.immutable.Map[Any,Any] = Map(1 -> I, II -> 2) 

scala> val intsToStrings = pairs collect { case pair: (Int, String) => pair } 

Il compilatore si lamenta ovviamente a causa del modello cancellazione tipo di JVM, quindi la prima cosa che cerchiamo sta usando tipi esistenziali:

scala> val intsToStrings = pairs collect { case pair: (_, _) => pair } 
intsToString: scala.collection.immutable.Map[Any,Any] = Map(1 -> I, II -> 2) 

Anche se il codice ha passato il compilatore e il risultato è "corretto" (volevamo coppie => abbiamo ottenuto coppie) non abbiamo ancora ottenuto ciò che volevamo realmente. Il secondo tentativo è simile al seguente:

scala> val intsToStrings = pairs collect { 
    | case pair: (_, _) if pair._1.isInstanceOf[Int] && pair._2.isInstanceOf[String] => pair 
    | } 
intsToStrings: scala.collection.immutable.Map[Any,Any] = Map(1 -> I) 

Ok, ci siamo quasi:

scala> val realIntsToRealStrings = intsToStrings map { 
    | pair => (pair._1.asInstanceOf[Int], pair._2.asInstanceOf[String]) 
    | } 
realIntsToRealStrings: scala.collection.immutable.Map[Int,String] = Map(1 -> I) 

Ce l'abbiamo fatta, ma invece di un solo getto (Any,Any)-(Int,String) abbiamo effettivamente copiato ogni coppia e così creato un nuova coppia

Ora arriva la domanda. Come ho detto "Il compilatore si lamenta, naturalmente ..." Ho fatto sembrare che io sappia davvero di cosa sto parlando. Io non! Tutto quello che so è che Java non aveva generici dall'inizio. A un certo punto i generici sono entrati in Java ma non nella JVM. Quindi il compilatore controlla tutti i tipi, ma non appena il codice è in esecuzione, JVM non si cura del tipo parametrico. Si vede solo che è un Map o un List ma non che sia un Map[String, Int] o List[Int].

Quindi ecco la mia domanda.

Con tutti i controlli, casting e mappatura, siamo riusciti a trasferire un Map[Any,Any] a Map[String,Int]. C'è un modo migliore per farlo? Voglio dire i tipi sono lì, JVM semplicemente non li vede (per quanto mi riguarda) ...

risposta

21
pairs collect { case p @ (_: Int, _: String) => p.asInstanceOf[(Int, String)] } 

o più conciso, ma con un po 'in testa, penso

pairs collect { case (x: Int, y: String) => (x, y) } 
+2

fredda thx ! Sapevo che Scala è abbastanza impressionante per farlo accadere;) – agilesteel

+2

Oh gioia! Nuovo personaggio speciale (@), l'ho quasi indovinato. – Ciantic