我有一个现有的case类,我想向其添加一个默认值的附加构造函数参数,并且不打扰现有的进行模式匹配的代码,但我找不到正确的方法。
即我有:
case class Foo(a: Int, b: Int)
def bar(n: Foo) = n match {
case Foo(1, 2) => true
case _ => false
}
现在,我需要向Foo添加一个附加参数c。即
case class Foo(a: Int, b: Int, c: Boolean = true)
在所有现有用例中,参数c
为true,因此具有该默认值。但是在某些新的用例中,需要为此传递false。
因此添加默认值为true
的另一个参数似乎是明智的。然而,一旦我这样做,bar
中的模式匹配就会变成语法错误。这似乎是错误的,因为我添加了默认的= true
以确保不需要修改现有的构造函数调用。
我该怎么做,并使旧模式匹配保持不变?
更新:请注意,我也不想重写所有现有的Foo实例。 @ som-snytt指出,我可以添加另一个参数作为Foo(a: Int, b: Int)(c: Boolean = true)
,这将是完美的,除了它会导致现有的调用(例如Foo(1,2)
)失败(必须将其重写为Foo(1,2)()
)。我正在寻找一种仅在某些用例中添加新参数的方法,并通过使用适用于其他任何地方的默认值来避免重写。
case Foo
语法不是在调用构造函数,而是在unapply
上调用称为object Foo
的方法。案例类会自动生成各种样板,包括伴随对象和取消应用。
unapply
仅具有一个参数,对象已匹配。这可以防止您重载它,因为您无法在Java / Scala中重载返回值。
总之,您不能完全做到自己想要的。
但是,您可以使用其他名称制作提取器。这是刚刚添加下划线的人:http://x3ro.de/multiple-unapply-methods-for-pattern-matching-in-scala/
也许在可能的情况下为提取器变量使用更有意义的名称会更好。
以下是有关其工作原理的更多信息:http://danielwestheide.com/blog/2012/11/21/the-neophytes-guide-to-scala-part-1-extractors.html
您可以写出case类“手动”执行的所有操作,并以不同的方式执行操作,例如不同的未应用操作,但是假设您关心equals,hashCode,toString以及所有这些,这将是非常令人讨厌的。如果这样做,则可以避免更改现有代码,但这似乎不值得。
以下是某人发布的示例:https://gist.github.com/okapies/2814608
也许你可以和case class Foo(a: Int, b: Int)(val c: Boolean = true)
一起生活。
更新:如果您几乎可以忍受,因为您不想在模式中使用额外的参数,那么可以做短一些的工作。
package fooplusplus
case class Foo(a: Int, b: Int) {
def c: Boolean = true
}
object Foo {
def apply(a: Int, b: Int, c: Boolean): Foo =
new {
private[this] val x = c // http://stackoverflow.com/a/12239654
} with Foo(a, b) {
override def c = x
}
}
object Test extends App {
def bar(x: Foo) = x match {
case Foo(1, 2) if !x.c => 3
case Foo(1, 2) => 2 // existing code
case _ => 1
}
Console println bar(Foo(1, 2))
Console println bar(Foo(1, 2, c = false))
Console println bar(Foo(0, 2))
}
如果您确实希望与新参数进行模式匹配,这是一种方法:
case class EnhancedFoo(a: Int, b: Int, c: Boolean)
class Foo(a: Int, b: Int, c: Boolean) extends EnhancedFoo(a, b, c)
object Foo {
def apply(a: Int, b: Int, c: Boolean = true): Foo = new Foo(a, b, c)
def unapply(x: Foo): Option[(Int, Int)] = Some(x.a, x.b)
}
object Test extends App {
def bar(x: EnhancedFoo) = x match {
case EnhancedFoo(1, 2, true) => 3
case Foo(1, 2) => 2 // existing code
case _ => 1
}
Console println bar(Foo(1, 2))
Console println bar(Foo(1, 2, c = false))
Console println bar(Foo(0, 2))
}
由于我们还没有做过任何真正的错误,因此如何处理:
scala> case class Foo(a: Int, b: Int, c: Boolean*)
defined class Foo
scala> import PartialFunction._
import PartialFunction._
scala> val foo = Foo(1,2)
f: Foo = Foo(1,2,WrappedArray())
scala> val goo = Foo(1,2,true)
g: Foo = Foo(1,2,WrappedArray(true))
scala> cond(foo) { case Foo(1,2) => true }
res0: Boolean = true
scala> cond(goo) { case Foo(1,2,false) => true }
res1: Boolean = false
布尔值变为三态,默认为旧式空。
scala> cond(foo) { case Foo(1,2, _ @ _*) => true }
res2: Boolean = true
scala> cond(foo) { case Foo(1,2, x) => true }
res3: Boolean = false
scala> cond(goo) { case Foo(1,2, x @ _*) if x exists identity => true }
res4: Boolean = true