Путаница в сопоставлении паттерна Scala с Option[Any]
У меня есть следующий код Scala.
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
Как я могу избежать предупреждений?
РЕДАКТИРОВАТЬ: Спасибо за предложения. Идея Дэниела хороша, но, похоже, не работает с общими типами, как в примере ниже
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
3 ответа
Это связано с типом стирания. JVM не знает ни одного параметра типа, кроме как с массивами. Из-за этого код Scala не может проверить, является ли Option
является Option[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
есть, но каков тип его содержимого - при условии, что есть какой-либо контент. None
будет падать на случай по умолчанию.
Любая информация о параметрах типа доступна только во время компиляции, а не во время выполнения (это называется стиранием типа). Это означает, что во время выполнения нет никакой разницы между Option[String]
а также Option[Int]
, поэтому любой шаблон, соответствующий типу Option[String]
также будет соответствовать Option[Int]
потому что во время выполнения оба просто Option
,
Поскольку это почти всегда не то, что вы намереваетесь, вы получите предупреждение. Единственный способ избежать предупреждения - это не проверять универсальный тип чего-либо во время выполнения (это хорошо, потому что это не работает так, как вы этого хотите в любом случае).
Там нет никакого способа проверить, является ли Option
является Option[Int]
или Option[String]
во время выполнения (кроме проверки содержимого, если это Some
).
Как уже говорилось, вы против здесь стирания.
Для решения... С актором 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 _ =>
}
}
}