为什么Scala在与@匹配模式时不会推断类型参数

时间:2014-08-19 17:33:17

标签: scala pattern-matching akka type-inference

我使用Scala 2.10.4和akka 2.3.4。我遇到了类型推断不符合我预期的问题。

下面的代码说明了我遇到的一个例子。我有一个案例类,它使用名为id的{​​{1}}来包装邮件。它使用消息类型进行参数化。然后我有一个名为MyMessage的有效负载,其中包含MyPayload

在一个actor中(这里我只是使用一个名为String的常规对象,因为问题不是akka特有的)我是模式匹配并调用一个对我的有效负载类型进行操作的函数MyObject

MyPayload

由于我不明白的原因,使用package so case class MyMessage[T](id:Long, payload:T) case class MyPayload(s:String) object MyObject { def receive:PartialFunction[Any, Unit] = { case m @ MyMessage(id, MyPayload(s)) => // Doesn't compile processPayload(m) // Compiles processPayload(MyMessage(id, MyPayload(s))) } def processPayload(m:MyMessage[MyPayload]) = { println(m) } } 和未应用的案例类进行模式修补并不能推断@的类型参数。在上面的代码中,我原以为MyMessage[T]的类型为m。但是,当我编译时,它认为类型是MyMessage[MyPayload]

MyMessage[Any]

这是预期的行为吗?如果是这样,我对Scala中的类型推断有什么误解?

3 个答案:

答案 0 :(得分:5)

您无法在模式匹配中提取类型参数 - 它是当前实现和/或运行时的限制。因为类型参数在运行时被擦除,所以需要很多开销来恢复它们 - 因此你不能使用在模式匹配中采用类型参数的unapply方法。

在您的情况下,它看起来更简单,因为编译器只能从提取器参数推断出类型。但一般来说,这并不容易,也可能就是为什么它甚至不适合你的情况。

有关此问题,请参阅this long living ticket

答案 1 :(得分:2)

您遇到的问题是类型删除

JVM在运行时期间对通用类型一无所知,请参阅:

How do I get around type erasure on Scala? Or, why can't I get the type parameter of my collections?

要使其编译,你必须详细告诉编译你期望的类型

 def receive:PartialFunction[Any, Unit] = {
    case message: MyMessage[MyPayload] =>
      processPayload(message)
  }

警告:这仍然会匹配任何MyMessage [_] ,并可能导致运行时异常

要在运行时确保类型,您需要使用TypeTags(请参阅上面的链接)

答案 2 :(得分:0)

奇怪的是它也适用于:

def receive: PartialFunction[Any, Unit] = {
 case m : MyMessage[MyPayload] => processPayload(m)
}

scala> MyObject.receive.isDefinedAt(MyMessage(12L, MyPayload("string")))
res9: Boolean = true
相关问题