Scala pattern matching confusion with Option[Any]

。_饼干妹妹 提交于 2019-12-03 06:32:46

问题


I have the following Scala code.

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:

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 unchecked warnings with the above as follows:

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

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 error warning is encountered: warning: abstract type T in type pattern T is unchecked since it is eliminated by erasure


回答1:


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 Option is an Option[Int] or an Option[String] -- that information has been erased.

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 Option is, but what the type of its contents are -- assuming there is any content. A None will fall through to the default case.




回答2:


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.

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 Option is an Option[Int] or an Option[String] at runtime (other than inspecting the content if it's a Some).




回答3:


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:

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


来源:https://stackoverflow.com/questions/3788358/scala-pattern-matching-confusion-with-optionany

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!