将参数默认添加到案例类中

问题描述 投票:2回答:2

我有一个现有的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)())。我正在寻找一种仅在某些用例中添加新参数的方法,并通过使用适用于其他任何地方的默认值来避免重写。

scala pattern-matching default-value
2个回答
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


1
投票

也许你可以和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
© www.soinside.com 2019 - 2024. All rights reserved.