为什么我不能对非案例类应用模式匹配?

时间:2016-08-09 14:23:48

标签: scala pattern-matching

是否有比#34更好的解释;这就是它的工作原理"。我的意思是我试过这个:

class TestShortMatch[T <: AnyRef] {
  def foo(t: T): Unit = {
    val f = (_: Any) match {
      case Val(t) => println(t)
      case Sup(l) => println(l)
    }
  }

  class Val(t: T)
  class Sup(l: Number)
}

和编译器投诉:

Cannot resolve symbol 'Val' Cannot resolve symbol 'Sup'

当然,如果我在每个类之前添加case,它将正常工作。但是原因是什么?编译器是否进行了一些优化并生成特定的字节码?

3 个答案:

答案 0 :(得分:5)

原因是双重的。模式匹配只是使用extractors的语法糖,而case classes恰好为您提供了一些免费的方法,其中一种是与主构造函数对应的提取器方法。

如果您希望上面的示例有效,则需要在对象unapplyVal中定义Sup方法。要做到这一点,您需要提取器方法(仅在val字段上定义,因此您必须创建字段val):

class Val[T](val t: T)
class Sup(val l: Number)

object Val {
   def unapply[T](v: Val[T]): Option[T] = Some(v.t)
}
object Sup {
   def unapply(s: Sup): Option[Number] = Some(s.l)
}

在哪一点上你可以做val Val(v) = new Val("hi")之类的事情。但是,通常情况下,最好让您的班级成为case班级。然后,你应该只定义额外的提取器。

通常的例子(我似乎无法找到参考)是坐标:

case class Coordinate(x: Double, val: Double)

然后您可以定义一个自定义提取器,如

object Polar {
  def unapply(c: Coordinate): Option[(Double,Double)] = {...}
}
object Cartesian {
  def unapply(c: Coordinate): Option[(Double,Double)] = Some((c.x,c.y))
}

转换为两种不同的表示形式,所有这些都在模式匹配时进行。

答案 1 :(得分:3)

您可以在任意类上使用模式匹配,但是您需要实现an unapply method,用于&#34;解构&#34;对象。

对于case类,unapply方法由编译器自动生成,因此您不需要自己实现它。

答案 2 :(得分:1)

当你写match exp { case Val(pattern) => ... case ... }时,这相当于这样:

match Val.unapply(exp) {
  case Some(pattern) =>
    ...
  case _ =>
    // code to match the other cases goes here
}

也就是说,它使用伴随对象的unapply方法的结果来查看匹配是否成功。

如果定义案例类,它会自动使用合适的unapply方法定义伴随对象。对于正常的课程,它没有。其动机与为案例类自动定义的其他事物(例如equalshashCode)相同:通过将类声明为案例类,您可以做一个关于你希望班级表现如何的陈述。鉴于此,自动生成的机会很有可能达到你想要的效果。对于一般课程,您可以根据自己的喜好来定义这些方法。

请注意,默认情况下,案例类的参数为val,对于普通类,该参数不是真的。因此,您的班级class Val(t: T)甚至无法从外部访问t。因此,甚至无法定义unapply方法,其值为t。这也是为什么你没有为普通课程自动生成unapply的另一个原因:除非所有参数都是val,否则甚至无法生成一个。{ / p>