首页 文章

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

提问于
浏览
3

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

下面的代码说明了我遇到的一个例子 . 我有一个案例类,它使用名为 MyMessageid 包装消息 . 它使用消息类型进行参数化 . 然后我有一个名为 MyPayload 的有效负载,其中包含 String .

在一个actor(这里我只是使用一个名为 MyObject 的常规对象,因为问题不是特定于akka)我是模式匹配并调用一个对我的有效负载类型 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)
  }
}

由于我不明白的原因,使用 @ 进行模式修补和未应用的case类不会推断出 MyMessage[T] 的类型参数 . 在上面的代码中,我原以为 m 的类型为 MyMessage[MyPayload] . 但是,当我编译时,它认为类型是 MyMessage[Any] .

[error] PatternMatch.scala:9: type mismatch;
[error]  found   : so.MyMessage[Any]
[error]  required: so.MyMessage[so.MyPayload]
[error] Note: Any >: so.MyPayload, but class MyMessage is invariant in type T.
[error] You may wish to define T as -T instead. (SLS 4.5)
[error]       processPayload(m)
[error]                      ^
[error] one error found
[error] (compile:compile) Compilation failed
[error] Total time: 1 s, completed Aug 19, 2014 12:08:04 PM

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

3 回答

  • 2

    您可以't extract type parameters in pattern matching - it is a limitation of the current implementation and/or the runtime. Because type parameters are erased at runtime it would require a lot of overhead to restore them - therefore you can' t使用 unapply 方法,该方法在模式匹配中采用类型参数 .

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

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

  • 0

    你遇到的问题是 type erasure

    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)
      }
    

    Warning: This will still match any MyMessage[_] 并且可能导致 runtime exceptions .

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

  • 5

    奇怪的是,它也适用于:

    def receive: PartialFunction[Any, Unit] = {
     case m : MyMessage[MyPayload] => processPayload(m)
    }
    
    scala> MyObject.receive.isDefinedAt(MyMessage(12L, MyPayload("string")))
    res9: Boolean = true
    

相关问题