在Option.isEmpty和Option.get上使用Option.map有什么好处?

时间:2016-08-12 10:02:32

标签: scala

我是来自Java背景的Scala新手,目前对考虑Option[T]的最佳做法感到困惑。

我觉得使用Option.map更具功能性和美观性,但这并不是说服其他人的好理由。有时,isEmpty检查感觉更直接,因此更具可读性。是否有客观上的优势,还是只是个人偏好?

示例:

变化1:

someOption.map{ value => 
  {
    //some lines of code
  }
} orElse(foo)

变化2:

if(someOption.isEmpty){
  foo
} else{
  val value = someOption.get
  //some lines of code
}

我故意排除了使用fold或模式匹配的选项。我现在对将Option视为一个集合的想法感到高兴,并且使用模式匹配进行简单的isEmpty检查是滥用模式匹配的恕我直言。但无论我为什么不喜欢这些选项,我都希望将这个问题的范围保持为标题中指定的上述两种变体。

3 个答案:

答案 0 :(得分:5)

  

有任何客观优势,还是个人偏好?

我认为客观优势与个人偏好之间存在细微差别。你不能让人相信任何一个人都有绝对的真理。

使用Scala构造的monadic性质所获得的最大优势是组合。将操作链接在一起而不必“担心”内部价值的能力非常强大,不仅适用于Option[T],还适用于Future[T]Try[T]Either[A, B]和在他们之间来回走动(另见Monad Transformers)。

让我们试着看看Option[T]上使用预定义方法如何帮助控制流程。例如,考虑一种情况,即只有大于某个值时才要求Option[Int],否则返回-1。在命令式方法中,我们得到:

val option: Option[Int] = generateOptionValue

var res: Int = if (option.isDefined) {
  val value = option.get
  if (value > 40) value * 2 else -1
} else -1

Option上使用集合样式方法,等价物如下所示:

val result: Int = option
  .filter(_ > 40)
  .map(_ * 2)
  .getOrElse(-1)

现在让我们考虑一下合成案例。假设我们有一个可能抛出异常的操作。此外,此操作可能会或可能不会产生价值。如果它返回一个值,我们想要用该值查询数据库,否则返回一个空字符串。

查看使用try-catch块的命令式方法:

var result: String = _
try {
  val maybeResult = dangerousMethod()
  if (maybeResult.isDefined) {
    result = queryDatabase(maybeResult.get)
  } else result = ""
}
catch {
  case NonFatal(e) => result = ""
}

现在让我们考虑使用scala.util.TryOption[String]并将两者组合在一起:

val result: String = Try(dangerousMethod())
  .toOption
  .flatten
  .map(queryDatabase)
  .getOrElse("")

我认为这最终归结为哪一个可以帮助您创建清晰的操作控制流程。习惯使用Option[T].map而非Option[T].get将使您的代码更安全

总结一下,我不相信有一个单一的事实。我相信组合可以导致美观,可读,副作用延迟安全代码,我全力以赴。我认为向他人展示你的感受的最佳方式是给我们看到的例子,并让他们感受到他们可以利用这些工具集的力量。

答案 1 :(得分:2)

  

使用模式匹配进行简单的isEmpty检查是滥用模式匹配的恕我直言

如果您只想进行isEmpty检查,isEmpty / isDefined完全没问题。但在你的情况下,你也想获得价值。使用模式匹配不是滥用;它恰恰是基本用例。使用get可以轻松地发出错误,例如忘记检查isDefined或进行错误检查:

if(someOption.isEmpty){
  val value = someOption.get
  //some lines of code
} else{
  //some other lines
}

希望测试会抓住它,但是没有理由接受#34;希望"。

组合符(map和朋友)优于get,因为模式匹配的原因相同:它们不允许您犯这种错误。在模式匹配和组合器之间进行选择是一个不同的问题。通常组合器是优选的,因为它们更易于组合(正如Yuval的答案所解释的那样)。如果你想做一个由单个组合器覆盖的东西,我通常会选择它们;如果您需要map ... getOrElse或带有多行分支的fold这样的组合,则视具体情况而定。

答案 2 :(得分:1)

GridLayoutManager的情况下看起来与您类似,但只考虑Option的情况。走出Future monad后,您将无法与未来的价值互动。

Future