假设我有一个可以接受可选参数的函数,Some如果参数是None,我想返回a,如果参数是,None则返回a Some:
def foo(a: Option[A]): Option[B] = a match {
case Some(_) => None
case None => Some(makeB())
}
Run Code Online (Sandbox Code Playgroud)
所以我想要做的就是反过来map.变体orElse不适用,因为它们保留了a它存在的价值.
有没有更简洁的方法来做到这一点if (a.isDefined) None else Some(makeB())?
fold比模式匹配更简洁
val op:Option[B] = ...
val inv = op.fold(Option(makeB()))(_ => None)
Run Code Online (Sandbox Code Playgroud)
这个答案概述:
foldfoldfold方案可能像解决方案一样"明显" if-else.解
您可以随时使用fold转换Option[A]为您想要的任何内容:
a.fold(Option(makeB())){_ => Option.empty[B]}
Run Code Online (Sandbox Code Playgroud)
演示
这是一个完整的可运行示例,包含所有必需的类型定义:
class A
class B
def makeB(): B = new B
def foo(a: Option[A]): Option[B] = a match {
case Some(_) => None
case None => Some(makeB())
}
def foo2(a: Option[A]): Option[B] =
a.fold(Option(makeB())){_ => Option.empty[B]}
println(foo(Some(new A)))
println(foo(None))
println(foo2(Some(new A)))
println(foo2(None))
Run Code Online (Sandbox Code Playgroud)
这输出:
None
Some(Main$$anon$1$B@5fdef03a)
None
Some(Main$$anon$1$B@48cf768c)
Run Code Online (Sandbox Code Playgroud)
为什么fold只似乎不太直观
在评论中,@ TheArchetypalPaul评论说,fold这个if-else解决方案似乎"不那么明显"了.
我会声称这主要是由于if-else布尔值的特殊语法的存在而产生的神器.
如果有像标准的东西
def ifNone[A, B](opt: Option[A])(e: => B) = new {
def otherwise[C >: B](f: A => C): C = opt.fold((e: C))(f)
}
Run Code Online (Sandbox Code Playgroud)
可以像这样使用的语法:
val optStr: Option[String] = Some("hello")
val reversed = ifNone(optStr) {
Some("makeB")
} otherwise {
str => None
}
Run Code Online (Sandbox Code Playgroud)
而且,更重要的是,如果在过去半个世纪发明的每种编程语言的每一个介绍的第一页上都提到了这种语法,那么ifNone-otherwise解决方案(即fold)对于大多数人来说看起来更自然.
事实上,该Option.fold方法是消除了的Option[T]类型:每当我们有一个Option[T],并希望得到一个A出来,期待最明显的事情应该是fold(a)(b)有a: A和b: T => A.相反与布尔值的特殊处理if-else-syntax(这仅仅是一种约定),该fold方法是非常基本的,事实上,它必须有能够从第一原理得出.
| 归档时间: |
|
| 查看次数: |
484 次 |
| 最近记录: |