我是来自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
检查是滥用模式匹配的恕我直言。但无论我为什么不喜欢这些选项,我都希望将这个问题的范围保持为标题中指定的上述两种变体。
答案 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.Try
和Option[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