Scala:Option [Boolean]有意义吗?

iye*_*and 6 api json boolean scala option

因此,Option[Int]或者Option[String]或者为此Option[A]导致Some(A)或者None,但是Boolean因为它本身代表双态(true/ false)而有所不同,它是否有意义Option[Boolean]?当JSON响应不应包含基于某些业务逻辑的布尔字段时,我经常面对这种情况.

有什么想法吗?

Tim*_*lds 10

这是正确的用法Option[Boolean].假设我有一个需要一些时间才能完成的正在运行的工作,我想要一个值来表示工作是否成功.这表明了类型的价值Option[Boolean].

  • 在工作完成之前,我不知道它是否成功,所以它有价值None.
  • 当工作完成时,它要么成功要么不成功,所以它有价值Some(true)Some(false).


mis*_*tor 10

选择性是您的数据类型的正交关注点.所以,是的,Option[Boolean]就像说的一样有意义Option[Int].

我们来谈谈你的特定用例.


如果业务规则说字段(比如说)isPrimeTime必须是类型Boolean,但是是可选的,那么你应该使用一个来建模Option[Boolean].

None在这种情况下,表明没有价值,Some(true)意味着"现在和真实",Some(false)意味着"现在和错误".这也允许您在代码中添加默认值,如下所示:

val isPrimeTime = json.getAs[Option[Boolean]]("isPrimeTime").getOrElse(false)
Run Code Online (Sandbox Code Playgroud)

您可以将各种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
}
Run Code Online (Sandbox Code Playgroud)

这似乎是一个巨大的浪费,因为你失去了可用的组合器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)
  }
}
Run Code Online (Sandbox Code Playgroud)

这仍然是一个重要的重复,您必须根据具体情况判断增加的清晰度是否弥补了它.

最近HaskellTips在twitter上提出了类似的建议,随后进行了类似的讨论.你可以在这里找到它.


有时,字段的存在与否是您可以编码为数据结构的决定.Option在这种情况下使用会出错.

这是一个例子.想象一下,有一个字段differentiator允许以下两种值.

// #1
{ "type": "lov", "value": "somethingFromSomeFixedSet" },

// #2
{ "type": "text", "value": "foo", "translatable": false }
Run Code Online (Sandbox Code Playgroud)

这里,假设该translatable字段是必填字段,但仅适用于""type":"text".

你可以这样建模Option:

case class Differentiator(
  _type: DifferentiatorType, 
  value: String, 
  translatable: Option[Boolean]
)
Run Code Online (Sandbox Code Playgroud)

然而,建模的更好方法是:

sealed trait Differentiator
case class Lov(value: String) extends Differentiator
case class Text(value: String, translatable: Boolean) extends Differentiator
Run Code Online (Sandbox Code Playgroud)

Yaron Minsky的有效ML演讲有一节关于此.你会发现它很有用.(尽管他使用ML来说明这些要点,但这个谈话非常容易理解,也适用于Scala程序员).