13

Recientemente tropecé con este post, que "introduce" el método collect para colecciones Scala. El uso es sencillo:Uso de recopilación en mapas en Scala

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

Ahora mapas son básicamente listas de pares de valores clave, que están representados por las tuplas de Scala. Por lo tanto es posible que quieras probar algo como esto:

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 } 

El compilador se queja, por supuesto, debido al modelo borrado tipo de la JVM, así que lo primero que tratamos está utilizando tipos existenciales:

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

Aunque el código pasó el compilador, y el resultado es "correcto" (queríamos pares => conseguimos pares) aún no obtuvimos lo que realmente queríamos. El segundo intento se ve así:

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, estamos casi allí:

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

Lo hicimos, pero en vez de solamente fundición (Any,Any)-(Int,String) que realmente copiamos cada par y por lo tanto creó una nuevo par.

Ahora viene la parte de la pregunta. Como mencioné "El compilador se queja, por supuesto ..." lo hice sonar como si realmente supiera de lo que estoy hablando. ¡Yo no! Todo lo que sé es que Java no tenía genéricos desde el principio. En algún momento, los genéricos ingresaron en Java pero no en la JVM. Entonces el compilador verifica todos los tipos, pero tan pronto como se ejecuta el código, a JVM no le importa el tipo paramétrico. Solo ve que es Map o List, pero no es que sea Map[String, Int] o List[Int].

Así que aquí está mi pregunta.

Con todo el control, la fundición y el mapeo, logramos transferir un Map[Any,Any] al Map[String,Int]. ¿Hay una mejor manera de hacerlo? Me refiero a los tipos están ahí, JVM simplemente no ver ellos (en lo que a mí respecta) ...

Respuesta

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

o más concisa, pero con algo de sobrecarga, creo

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

THX fresca ! Sabía que Scala es lo suficientemente impresionante como para hacerlo posible;) – agilesteel

+2

¡Oh, alegría! Nuevo personaje especial (@), casi lo adiviné. – Ciantic