2010-09-24 13 views
28

Tengo el siguiente código de Scala.Confusión de coincidencia del patrón de Scala con la opción [Cualquiera]

import scala.actors.Actor 

object Alice extends Actor { 
    this.start 
    def act{ 
    loop{ 
     react { 
     case "Hello" => sender ! "Hi" 
     case i:Int => sender ! 0 
     } 
    } 
    } 
} 
object Test { 
    def test = { 
    (Alice !? (100, "Hello")) match { 
     case i:Some[Int] => println ("Int received "+i) 
     case s:Some[String] => println ("String received "+s) 
     case _ => 
    } 
    (Alice !? (100, 1)) match { 
     case i:Some[Int] => println ("Int received "+i) 
     case s:Some[String] => println ("String received "+s) 
     case _ => 
    } 
    } 
} 

Después de hacer Test.test, me sale la salida:

scala> Test.test 
Int received Some(Hi) 
Int received Some(0) 

que estaba esperando la salida

String received Some(Hi) 
Int received Some(0) 

¿Cuál es la explicación?

Como una segunda pregunta, me sale unchecked advertencias con lo anterior de la siguiente manera:

C:\scalac -unchecked a.scala 
a.scala:17: warning: non variable type-argument Int in type pattern Some[Int] is unchecked since it is eliminated by erasure 
     case i:Some[Int] => println ("Int received "+i) 
      ^
a.scala:18: warning: non variable type-argument String in type pattern Some[String] is unchecked since it is eliminated by erasure 
     case s:Some[String] => println ("String received "+s) 
      ^
a.scala:22: warning: non variable type-argument Int in type pattern Some[Int] is unchecked since it is eliminated by erasure 
     case i:Some[Int] => println ("Int received "+i) 
      ^
a.scala:23: warning: non variable type-argument String in type pattern Some[String] is unchecked since it is eliminated by erasure 
     case s:Some[String] => println ("String received "+s) 
      ^
four warnings found 

¿Cómo puedo evitar las advertencias?

EDIT: Gracias por las sugerencias. La idea de Daniel es agradable, pero no parece trabajar con tipos genéricos, como en el siguiente ejemplo

def test[T] = (Alice !? (100, "Hello")) match { 
    case Some(i: Int) => println ("Int received "+i) 
    case Some(t: T) => println ("T received ") 
    case _ => 
} 

La siguiente error se encuentra advertencia: warning: abstract type T in type pattern T is unchecked since it is eliminated by erasure

Respuesta

36

Esto se debe al tipo-borrado. La JVM no conoce ningún parámetro de tipo, excepto en las matrices. Debido a eso, el código Scala no puede verificar si un Option es un Option[Int] o un Option[String] - esa información ha sido borrada.

Usted puede arreglar su código de esta manera, sin embargo:

object Test { 
    def test = { 
    (Alice !? (100, "Hello")) match { 
     case Some(i: Int) => println ("Int received "+i) 
     case Some(s: String) => println ("String received "+s) 
     case _ => 
    } 
    (Alice !? (100, 1)) match { 
     case Some(i: Int) => println ("Int received "+i) 
     case Some(s: String) => println ("String received "+s) 
     case _ => 
    } 
    } 
} 

De esta manera no se está probando lo que el tipo de Option es, pero lo que el tipo de su contenido es - suponiendo que no es ningún contenido. Un None caerá al caso predeterminado.

+0

Gracias! Las otras respuestas también son buenas, incluida la solución sugerida por Kevin. Pero esta parece ser la forma más elegante de arreglar mi código sin demasiada reescritura. – Jus12

+0

¿Puede sugerir una solución similar para los tipos genéricos? como en: 'def test [T] = (Alice!? (100," Hello ")) match {case Some (t: T) => println (" T received "); case _ => println ("algo más recibido")} ' – Jus12

+1

@ Jus12 De esa manera no funcionará. Tendrá que obtener un 'm: Manifiesto [T]', luego haga algo como 'case Some (t: T) if m.erasure.isAssignableFrom (t.getClass()) =>'. –

8

Cualquier información sobre los parámetros de tipo sólo está disponible en tiempo de compilación -tiempo, no en tiempo de ejecución (esto se conoce como borrado de tipo). Esto significa que en el tiempo de ejecución no hay diferencia entre Option[String] y Option[Int], por lo que cualquier coincidencia de patrón en el tipo Option[String], también coincidirá con Option[Int] porque en el tiempo de ejecución ambos son solo Option.

Dado que esto casi siempre no es lo que pretende, recibe una advertencia. La única forma de evitar la advertencia es no verificar el tipo genérico de algo en tiempo de ejecución (lo cual está bien porque de todos modos no funciona como usted quiere).

No hay manera de comprobar si un Option es un Option[Int] o un Option[String] en tiempo de ejecución (que no sea la inspección del contenido si es un Some).

2

Como ya se indicó, usted está en contra de la eliminación aquí.

Para la solución ... Es normal con Scala actor para definir las clases de casos para cada tipo de mensaje es muy probable que enviar:

case class MessageTypeA(s : String) 
case class MessageTypeB(i : Int) 

object Alice extends Actor { 
    this.start 
    def act{ 
    loop{ 
     react { 
     case "Hello" => sender ! MessageTypeA("Hi") 
     case i:Int => sender ! MessageTypeB(0) 
     } 
    } 
    } 
} 
object Test { 
    def test = { 
    (Alice !? (100, "Hello")) match { 
     case Some(MessageTypeB(i)) => println ("Int received "+i) 
     case Some(MessageTypeA(s)) => println ("String received "+s) 
     case _ => 
    } 
    (Alice !? (100, 1)) match { 
     case Some(MessageTypeB(i)) => println ("Int received " + i) 
     case Some(MessageTypeA(s)) => println ("String received " + s) 
     case _ => 
    } 
    } 
} 
Cuestiones relacionadas