我正在使用Scala 2.10.4和akka 2.3.4 . 我遇到了类型推断不符合我预期的问题 .
下面的代码说明了我遇到的一个例子 . 我有一个案例类,它使用名为 MyMessage
的 id
包装消息 . 它使用消息类型进行参数化 . 然后我有一个名为 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 回答
您可以'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 .
你遇到的问题是 type erasure
JVM在运行时期间对通用类型一无所知,请参阅:
How do I get around type erasure on Scala? Or, why can't I get the type parameter of my collections?
为了使其编译,您必须详细告诉编译您期望的类型
Warning: This will still match any MyMessage[_] 并且可能导致 runtime exceptions .
要在运行时确保类型,您需要使用TypeTags(请参阅上面的链接)
奇怪的是,它也适用于: