34

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

4

3 回答 3

50

这是由于类型擦除。JVM 不知道任何类型参数,除了数组。因此,Scala 代码无法检查 anOption是 anOption[Int]还是 an 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是什么,而是它的内容是什么类型——假设有任何内容。ANone将进入默认情况。

于 2010-09-24T16:48:52.180 回答
8

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

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

没有办法在运行时检查 anOption是 anOption[Int]还是 an Option[String](除了检查内容是否是 a Some)。

于 2010-09-24T15:16:07.823 回答
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 _ =>
    }
  }
}
于 2010-09-24T16:40:34.313 回答