Scala 模式匹配与 Option[Any] 混淆
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3788358/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Scala pattern matching confusion with Option[Any]
提问by Jus12
I have the following Scala code.
我有以下 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 _ =>
}
}
}
After doing Test.test, I get the output:
完成后Test.test,我得到输出:
scala> Test.test
Int received Some(Hi)
Int received Some(0)
I was expecting the output
我期待输出
String received Some(Hi)
Int received Some(0)
What is the explanation?
解释是什么?
As a second question, I get uncheckedwarnings with the above as follows:
作为第二个问题,我收到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
How can I avoid the warnings?
我怎样才能避免警告?
EDIT: Thanks for the suggestions. Daniel's idea is nice but does not seem to work with generic types, as in the example below
编辑:感谢您的建议。Daniel 的想法很好,但似乎不适用于泛型类型,如下例所示
def test[T] = (Alice !? (100, "Hello")) match {
case Some(i: Int) => println ("Int received "+i)
case Some(t: T) => println ("T received ")
case _ =>
}
The following errorwarning is encountered: warning: abstract type T in type pattern T is unchecked since it is eliminated by erasure
遇到以下错误警告:warning: abstract type T in type pattern T is unchecked since it is eliminated by erasure
回答by Daniel C. Sobral
This is due to type-erasure. The JVM does not know of any type parameter, except on arrays. Because of that, Scala code can't check whether an Optionis an Option[Int]or an Option[String]-- that information has been erased.
这是由于类型擦除。JVM 不知道任何类型参数,数组除外。因此,Scala 代码无法检查 anOption是 anOption[Int]还是 an Option[String]—— 该信息已被删除。
You could fix your code this way, though:
不过,您可以通过这种方式修复代码:
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 _ =>
}
}
}
This way you are not testing what the type of Optionis, but what the type of its contents are -- assuming there is any content. A Nonewill fall through to the default case.
通过这种方式,您不是在测试类型Option是什么,而是在测试其内容的类型——假设有任何内容。ANone将落入默认情况。
回答by sepp2k
Any information about type parameters is only available at compile-time, not at runtime (this is known as type erasure). This means that at runtime there is no difference between Option[String]and Option[Int], so any pattern matching on the type Option[String], will also match Option[Int]because at runtime both is just Option.
有关类型参数的任何信息仅在编译时可用,而不在运行时可用(这称为类型擦除)。这意味着在运行时Option[String]和之间没有区别Option[Int],因此类型上的任何模式匹配Option[String]也将匹配,Option[Int]因为在运行时两者都只是Option。
Since this is almost always not what you intend, you get a warning. The only way to avoid the warning is not to check the generic type of something at runtime (which is fine because that doesn't work like you want it to anyway).
由于这几乎总是不是您想要的,因此您会收到警告。避免警告的唯一方法是不要在运行时检查某些东西的通用类型(这很好,因为无论如何它都不会像您希望的那样工作)。
There is no way to check whether an Optionis an Option[Int]or an Option[String]at runtime (other than inspecting the content if it's a Some).
没有办法在运行时检查 anOption是 anOption[Int]还是 an Option[String](除了检查内容是否是 a Some)。
回答by Kevin Wright
As already stated, you're up against erasure here.
如前所述,您在这里反对擦除。
For the solution... It's normal with Scala actor to define case classes for each message type you're likely to send:
对于解决方案......使用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 _ =>
}
}
}

