3
abstract class Animal

case class Cat(name: String) extends Animal

case class Dog(name: String) extends Animal

假设我已经定义了 Cat 和 Dog,两个案例类。

然后我像这样使用它们:

val animal = createAnimal
animal match {
  case Dog(anyName) => "this is a dog"
  case Cat("kitty") => "this is a cat named kitty"
  case _ => "other animal"
}

如果我将字节码反编译为 Java,我会得到如下信息:

Animal animal = createAnimal();
String result = "other animal";

if (animal instanceof Dog) {
    result = "this is a dog";
} else if (animal instanceof Cat) {
    Cat cat = (Cat) animal;
    if (cat.name() == "kitty") {
        result = "this is a cat named kitty";
    }
}

return result;

编译器为 Cat 和 Dog 生成 unapply 方法,但它们不用于模式匹配代码。

这是为什么?

4

2 回答 2

4

从 Scala 语言的角度来看这个问题,实现按规范要求工作。见http://www.scala-lang.org/docu/files/ScalaReference.pdf

在 §5.3.2 中,案例类被定义为在伴随(提取器)对象中包含 unapply 的实现。

然而,当我们进入模式匹配(第 8.1 节)时,案例类有自己的匹配部分,第 8.1.6 节,它根据构造函数的参数指定它们在模式匹配中的行为,而不引用已经生成的取消应用/取消应用序列:

8.1.6 构造函数模式

句法:

SimplePattern ::= StableId '(' [Patterns] ')

构造函数模式的形式为 c(p1,…,pn),其中 n≥0。它由一个稳定的标识符 c 组成,后跟元素模式 p1,…,pn。构造函数 c 是一个简单的或限定的名称,它表示一个案例类。如果case类是单态的,那么它必须符合模式的期望类型,并且x的主构造函数的形参类型被作为元素模式p1,…,pn的期望类型。如果 case 类是多态的,则实例化其类型参数,以便 c 的实例化符合模式的预期类型。然后将 c 的主构造函数的实例化形式参数类型作为组件模式 p1,…,pn 的预期类型。该模式匹配从构造函数调用创建的所有对象 c(v1,...,

文档继续在 §8.1.8 中描述 unapply/unapplySeq 的使用;但这是规范的一个单独的、不相交的部分,它适用于不是案例类的类。

因此,您可以认为 unapply 是一种在您自己的代码中使用的有用方法,但不是 scala 语言中的模式匹配所必需的。

于 2014-06-15T11:12:50.307 回答
2

我的猜测是这是一个优化 scalac 执行。该unapply方法是合成的,因此编译器知道它的实现并且可能会提高运行时性能。

如果该理论是正确的,则以下内容应该有所不同:

object Cat {
  def unapply(c: Cat): Option[String] = Some(c.name)
}
class Cat(val name: String) extends Animal
于 2014-06-15T08:26:23.687 回答