是否有比#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
,它将正常工作。但是原因是什么?编译器是否进行了一些优化并生成特定的字节码?
答案 0 :(得分:5)
原因是双重的。模式匹配只是使用extractors的语法糖,而case classes恰好为您提供了一些免费的方法,其中一种是与主构造函数对应的提取器方法。
如果您希望上面的示例有效,则需要在对象unapply
和Val
中定义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
方法定义伴随对象。对于正常的课程,它没有。其动机与为案例类自动定义的其他事物(例如equals
和hashCode
)相同:通过将类声明为案例类,您可以做一个关于你希望班级表现如何的陈述。鉴于此,自动生成的机会很有可能达到你想要的效果。对于一般课程,您可以根据自己的喜好来定义这些方法。
请注意,默认情况下,案例类的参数为val
,对于普通类,该参数不是真的。因此,您的班级class Val(t: T)
甚至无法从外部访问t
。因此,甚至无法定义unapply
方法,其值为t
。这也是为什么你没有为普通课程自动生成unapply
的另一个原因:除非所有参数都是val
,否则甚至无法生成一个。{ / p>