当前位置: 首页 > 知识库问答 >
问题:

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

范翰海
2023-03-14

在一个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中的类型推断有什么误解?

共有1个答案

周和安
2023-03-14

您不能在模式匹配中提取类型参数--这是当前实现和/或运行时的一个限制。由于类型参数是在运行时擦除的,因此恢复它们需要大量开销-因此不能使用unapply方法在模式匹配中使用类型参数

在您的例子中,它看起来更简单,因为编译器可以仅仅从提取器参数推断类型。但一般来说,这不是那么容易的,这可能是为什么它在你的情况下不起作用的原因。

看看这张关于这个问题的活生生的罚单。

 类似资料:
  • 我想消除此示例代码中的类型擦除警告: 它编译和工作正常,但有一个警告: 警告:(31,13)类型模式Seq[Int](Seq[Int]的底层)中的非变量类型参数Int未选中,因为它被擦除情况b消除:Seq[Int]= 在这种情况下,你有什么简单的解决方案来避免擦除吗? 到目前为止,我尝试了什么(根据这一点): 但是它不能编译,因为c现在是Any类型。 我相信这个问题有几种解决方法。我会接受最简单的

  • 假设我们有一个泛型类: 然后,我们希望将与和的进行模式匹配:

  • 定义以下结构: 和下面的函数(请注意,第二行是类型检查错误点,它也是一个短路结果的算法错误,但它还是出现了,我想知道为什么类型检查没有发现它) 我知道scala也有类型擦除的问题,但我很惊讶在这种情况下,在编译时却检测不到这一点?在本例中是,而显然属于类型? 听起来这里有一个很长的解释https://gist.github.com/jkpl/5279EE05CCA8CC1EC452FC26ACE5

  • 我有一个从提取的代码,对于多个子类来说,这个代码看起来应该完全相同,所以我尽量避免重复。但是,实际上(见下文),scala认为是一个泛型的,返回的值类型为,当然,它没有和方法。 问题是在这里避免重复的适当方法是什么?我对将转换为字符串并不那么着迷,因为这段代码可以使用刚从字符串解析为AST的json。我开始考虑为我需要的三种类型编写包装器,并将这些类型的匹配和隐式转换器转换为包装器,然后为这些包装