【问题标题】:Scala pattern matching confusion with Option[Any]Scala 模式匹配与 Option[Any] 混淆
【发布时间】:2011-04-16 20:17:14
【问题描述】:

我有以下 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

如何避免这些警告?

编辑:感谢您的建议。 Daniel 的想法不错,但似乎不适用于泛型类型,如下例所示

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

【问题讨论】:

    标签: scala pattern-matching actor unchecked


    【解决方案1】:

    有关类型参数的任何信息仅在编译时可用,而不是在运行时可用(这称为类型擦除)。这意味着在运行时Option[String]Option[Int] 之间没有区别,因此任何与Option[String] 类型匹配的模式也将匹配Option[Int],因为在运行时两者都只是Option

    由于这几乎总是不是您想要的,因此您会收到警告。避免警告的唯一方法是不在运行时检查某事物的泛型类型(这很好,因为无论如何它都不会像您希望的那样工作)。

    无法在运行时检查OptionOption[Int] 还是Option[String](除了检查内容是否为Some)。

    【讨论】:

      【解决方案2】:

      如前所述,您在这里面临擦除。

      对于解决方案... 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 _ =>
          }
        }
      }
      

      【讨论】:

        【解决方案3】:

        这是由于类型擦除造成的。 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 的类型,而是测试其内容的类型——假设有任何内容。 None 将采用默认情况。

        【讨论】:

        • 谢谢!其他答案也很好,包括凯文建议的解决方法。但这似乎是无需大量重写即可修复我的代码的最优雅方法。
        • 您能否为泛型类型提出类似的解决方法?如:def test[T] = (Alice !? (100, "Hello")) match { case Some(t: T) => println ("T received "); case _ => println ("something else received") }
        • @Jus12 这种方式行不通。您需要获得m: Manifest[T],然后执行case Some(t: T) if m.erasure.isAssignableFrom(t.getClass()) => 之类的操作。
        • @DanielC.Sobral 您添加的更改是case Some(Int) 而不是case x: Some[Int](对于字符串也是如此),是吗?为什么这很重要?
        • @Kevin 这就是我在第一段中解释的内容。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-23
        • 1970-01-01
        相关资源
        最近更新 更多