2010-09-24 6 views
28

У меня есть следующий код Scala.Scala pattern confusion with 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 _ => 
    } 
    } 
} 

После этого Test.test, я получаю выход:

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

я ожидал выход

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

Что такое объяснение?

В качестве второго вопроса, я получаю unchecked предупреждения с вышеупомянутыми следующим образом:

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 

Как я могу избежать предупреждений?

EDIT: Спасибо за предложения. Идея Даниила хороша, но не похоже на работу с родовыми типами, как в примере ниже

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

Следующая ошибка предупреждение встречается: warning: abstract type T in type pattern T is unchecked since it is eliminated by erasure

ответ

36

Это происходит из-за типа стирания. JVM не знает ни одного параметра типа, кроме массивов. Из-за этого код Scala не может проверить, является ли OptionOption[Int] или Option[String] - эта информация была удалена.

Вы можете исправить свой код таким образом, хотя:

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

Таким образом, вы не испытывая то, что тип Option, но что тип его содержания - если есть какое-либо содержимое. A None пройдёт к случаю по умолчанию.

+0

Спасибо! Другие ответы тоже хороши, в том числе обходное решение Кевина. Но это самый элегантный способ исправить мой код без большой перезаписи. – Jus12

+0

Можете ли вы предложить подобное обходное решение для общих типов? как в: 'def test [T] = (Alice!? (100,« Hello »)) match {case Some (t: T) => println (« T получено »); case _ => println ("something else received")} ' – Jus12

+1

@ Jus12 Этот способ не будет работать. Вам нужно получить 'm: Manifest [T]', а затем сделать что-то вроде 'case Some (t: T), если m.erasure.isAssignableFrom (t.getClass()) =>'. –

8

Любая информация о параметрах типа доступен только при компиляции -time, а не во время выполнения (это называется стиранием типа). Это означает, что во время выполнения нет разницы между и Option[Int], поэтому любое сопоставление шаблонов по типу Option[String] также будет соответствовать Option[Int], потому что во время выполнения оба равно Option.

Поскольку это почти всегда не то, что вы намереваетесь, вы получаете предупреждение. Единственный способ избежать предупреждения - не проверять общий тип чего-то во время выполнения (что хорошо, потому что это не работает так, как вы этого хотите).

Там нет никакого способа проверить, является ли Option является Option[Int] или Option[String] во время выполнения (кроме проверки содержимого, если это Some).

2

Как уже говорилось, вы против стирания здесь.

Для решения ... Это нормально с Scala актером, чтобы определить классы случая для каждого типа сообщения вы, вероятно, отправить:

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