Scala совпадение шаблонов с опцией [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
Как избежать предупреждений?
EDIT: Спасибо за предложения. Идея Даниэля хороша, но, похоже, не работает с родовыми типами, как в примере ниже
def test[T] = (Alice !? (100, "Hello")) match {
case Some(i: Int) => println ("Int received "+i)
case Some(t: T) => println ("T received ")
case _ =>
}
Появляется следующее предупреждение error: warning: abstract type T in type pattern T is unchecked since it is eliminated by erasure
Ответы
Ответ 1
Это связано с стиранием типа. 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
, но какой тип его содержимого - при условии наличия какого-либо контента. A None
пройдёт к случаю по умолчанию.
Ответ 2
Любая информация о параметрах типа доступна только во время компиляции, а не во время выполнения (это называется стиранием типа). Это означает, что во время выполнения нет разницы между Option[String]
и Option[Int]
, поэтому любое сопоставление шаблонов в типе Option[String]
также будет соответствовать Option[Int]
, потому что во время выполнения оба просто Option
.
Так как это почти всегда не то, что вы намереваетесь, вы получаете предупреждение. Единственный способ избежать предупреждения - не проверять общий тип чего-то во время выполнения (это нормально, потому что это не работает так, как вы этого хотите).
Невозможно проверить, является ли Option
Option[Int]
или Option[String]
во время выполнения (кроме проверки содержимого, если оно Some
).
Ответ 3
Как уже говорилось, вы против стирания здесь.
Для решения... Это нормально с Scala actor для определения классов случаев для каждого типа сообщения, которое вы, скорее всего, будете отправлять:
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 _ =>
}
}
}