鉴于
case class Foo (
x: Int = 1,
y: String,
)
实例化所述类的最佳方法是什么,只有在满足局部条件时才覆盖默认参数(例如,对应于构造函数参数的局部变量不是None)
object Test {
/* Let's pretend I cannot know the state of x,y
* because they come from the network, a file... */
val x: Option[Int] = getX()
val y: Option[String] = getY()
Foo(
x=???, // how to get x=if(x.isDefined) x else "use default of Foo" here
y=y.get,
)
}
检查条件和以不同方式实例化案例类的直接解决方案不会缩放(具有默认值的七个参数 - > 128个不同的实例化)
解决方案1)我知道的一个解决方案是:
object Foo {
val Defaults = Foo(y="")
}
object Test {
val x: Option[Int] = getX()
val y: Option[String] = getY()
Foo(
x=x.getOrElse(Foo.Defaults.x)
y=y.get
)
}
这很好用。当y为None时,我得到NoSuchElementException,但这没关系,因为它是一个必需的构造函数参数。然而,这显然是一个黑客,并且有一个明显的缺点,即可以写:
Foo(
x=x.getOrElse(Foo.Defaults.x)
y=y.getOrElse(Foo.Defaults.y)
)
当y为None时,您会得到y的非感性默认值。
解决方案2)另一种解决方案如下:
sealed trait Field
case object X extends Field
object Foo {
private val template = Foo(y="")
val Defaults = {
case X => template.x
}
}
object Test {
val x: Option[Int] = getX()
val y: Option[String] = getY()
Foo(
x=x.getOrElse(Foo.Defaults(X))
y=y.get
)
}
这在安全性方面要好一些,但现在我必须为每个默认参数创建一个类型。
正确简洁的解决方案是什么样的?
答案 0 :(得分:1)
我不清楚你如何做得比以下更好:
object Foo { def apply(optX: Option[Int], optY: Option[String]): Foo = Foo(optX.getOrElse(1), optY.get) }
case class Foo private(x: Int, y: String)
Foo(Some(5), None) // fails with NoSuchElementException
Foo(Some(5), Some("Hi")) // succeeds in creating Foo(5, "Hi")
Foo(None, Some("Hi")) // succeeds in creating Foo(1, "Hi"), note the default value of x
参数是必需的还是带有默认值的可选参数是通过前者get
的调用和后者getOrElse
的调用来编码的。
当然,您可以包含Option
的{{1}}方法,以便在省略所需参数时提供更有意义的消息。
我意识到距离您的解决方案1并不远,可能无法满足您的需求。