2010-09-24 10 views
28

Ho il seguente codice Scala.Confusione corrispondenza modello Scala con Option [Any]

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 _ => 
    } 
    } 
} 

Dopo aver fatto Test.test, ottengo l'output:

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

mi aspettavo l'uscita

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

Qual è la spiegazione?

Come una seconda domanda, ottengo unchecked avvertimenti con quanto sopra come segue:

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 

Come posso evitare gli avvertimenti?

EDIT: Grazie per i suggerimenti. L'idea di Daniel è bello, ma non sembra funzionare con tipi generici, come nell'esempio qui sotto

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

Il seguente errore si verifica avvertimento: warning: abstract type T in type pattern T is unchecked since it is eliminated by erasure

risposta

36

Ciò è dovuto al tipo-cancellazione. La JVM non conosce alcun parametro di tipo, ad eccezione degli array. Per questo motivo, il codice di Scala non può controllare se uno Option è un Option[Int] o un Option[String] - quell'informazione è stata cancellata.

Si potrebbe risolvere il codice in questo modo, però:

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 _ => 
    } 
    } 
} 

In questo modo non si sta verificando quello che il tipo di Option è, ma ciò che il tipo di suoi contenuti sono - non assumendo è alcun contenuto. A None passerà al caso predefinito.

+0

Grazie! Anche le altre risposte sono buone, compresa la soluzione suggerita da Kevin. Ma questo sembra il modo più elegante per sistemare il mio codice senza molto riscrivere. – Jus12

+0

Puoi suggerire una soluzione alternativa simile per i tipi generici? come in: 'def test [T] = (Alice!? (100," Ciao ")) match {case Some (t: T) => println (" T received "); case _ => println ("qualcos'altro ricevuto")} ' – Jus12

+1

@ Jus12 In questo modo non funzionerà. Avrai bisogno di ottenere un 'm: Manifest [T]', quindi fare qualcosa come 'case Some (t: T) se m.erasure.isAssignableFrom (t.getClass()) =>'. –

8

Tutte le informazioni sui parametri di tipo è disponibile solo in fase di compilazione -time, non in fase di esecuzione (questo è noto come cancellazione del tipo). Ciò significa che in fase di esecuzione non vi è alcuna differenza tra Option[String] e Option[Int], quindi qualsiasi modello corrispondente sul tipo Option[String] corrisponderà anche a Option[Int] perché in fase di esecuzione entrambi sono solo Option.

Poiché questo non è quasi sempre ciò che si intende, viene visualizzato un avviso. L'unico modo per evitare l'avviso è non controllare il tipo generico di qualcosa in fase di esecuzione (che va bene perché non funziona come lo vuoi comunque).

Non v'è alcun modo per verificare se un Option è un Option[Int] o un Option[String] in fase di esecuzione (diverso ispezionare il contenuto se è un Some).

2

Come già detto, sei qui contro la cancellazione.

Per la soluzione ... E 'normale con l'attore Scala per definire classi case per ogni tipo di messaggio è molto probabile da inviare:

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 _ => 
    } 
    } 
} 
Problemi correlati