因此,Option[Int]
或Option[String]
或Option[A]
会产生Some(A)
或None
,但Boolean
会因此而异。固有地表示双重状态(true
/ false
),有Option[Boolean]
是否有意义?当JSON
响应不应包含基于某些业务逻辑的布尔字段时,我会经常遇到这种情况。
有什么想法?
答案 0 :(得分:10)
这是对Option[Boolean]
的正确使用。假设我有一个需要一些时间才能完成的正在运行的工作,我想要一个值来表示工作是否成功。这表示类型Option[Boolean]
的值。
None
。 Some(true)
或Some(false)
。答案 1 :(得分:8)
选项性是您的数据类型的正交关注点。是的,Option[Boolean]
和Option[Int]
一样有意义。
让我们谈谈您的特定用例。
如果业务规则说明字段(例如)isPrimeTime
必须是Boolean
类型,但是可选,那么您应该使用Option[Boolean]
对其进行建模。
None
表示缺少值,Some(true)
表示“现在和真实”,Some(false)
表示“存在和错误”。这也允许您在代码中添加默认值,如下所示:
val isPrimeTime = json.getAs[Option[Boolean]]("isPrimeTime").getOrElse(false)
您可以将各种Option
组合器用于此类设置中出现的其他常见用例。 (我会让你的想象力发挥作用。)
如果你的域名中有很多这些“三态”字段,并且如果第三个状态表明某些特定于域的想法,那么从上下文中看不出这一点,我强烈建议你创建自己的总和类型。即使你在技术上仍然可以使用Option[Boolean]
,这可能不利于你的理智。这是一个例子。
sealed trait SignalValueIndication
case class Specified(value: Boolean) extends SignalValueIndication
case object DontCare extends SignalValueIndication
// Use
val signalValue = signalValueIndication match {
case Specified(value) => value
case DontCare => chooseOptimalSignalValueForImpl
}
这似乎是一个巨大的浪费,因为你正在失去Option
上可用的组合器。这部分是正确的。部分原因是因为这两种类型是同构的,所以写桥不会那么难。
sealed trait SignalValueIndication {
// ...
def toOption: Option[Boolean] = this match {
case Specified(value) => Some(value)
case DontCare => None
}
def getOrElse(fallback: => Boolean) = this.toOption.getOrElse(fallback)
}
object SignalValueIndication {
def fromOption(value: Option[Boolean]): SignalValueIndication = {
value.map(Specified).getOrElse(DontCare)
}
}
这仍然是一个重要的重复,您必须根据具体情况判断增加的清晰度是否弥补了这一点。
HaskellTips最近在Twitter上提出了类似的建议,随后进行了类似的讨论。你可以找到它here。
有时,字段的存在与否是您可以编码为数据结构的决定。在这种情况下使用Option
会出错。
这是一个例子。想象一下,有一个字段differentiator
,允许使用以下两种值。
// #1
{ "type": "lov", "value": "somethingFromSomeFixedSet" },
// #2
{ "type": "text", "value": "foo", "translatable": false }
这里假设translatable
字段是必填字段,但仅适用于“”type“:”text“。
您可以使用Option
对其进行建模:
case class Differentiator(
_type: DifferentiatorType,
value: String,
translatable: Option[Boolean]
)
然而,建模的更好方法是:
sealed trait Differentiator
case class Lov(value: String) extends Differentiator
case class Text(value: String, translatable: Boolean) extends Differentiator
Yaron Minsky的Effective ML谈话有一节关于此。你会发现它很有用。 (尽管他使用ML来说明这些要点,但这个谈话非常容易理解,也适用于Scala程序员。)