假设我有一个可以接受可选参数的函数,如果参数为Some
,我想返回None
,如果参数为{{1},我想返回None
}:
Some
所以我想做的就是def foo(a: Option[A]): Option[B] = a match {
case Some(_) => None
case None => Some(makeB())
}
的倒数。 map
的变体不适用,因为如果它存在,它们会保留orElse
的值。
有没有比a
更简洁的方法呢?
答案 0 :(得分:8)
折叠比模式匹配更简洁
val op:Option[B] = ...
val inv = op.fold(Option(makeB()))(_ => None)
答案 1 :(得分:6)
这个答案概述:
fold
fold
fold
- 解决方案可能与if-else
- 解决方案一样“显而易见”。<强>解决方案强>
您始终可以使用fold
将Option[A]
转换为您想要的内容:
a.fold(Option(makeB())){_ => Option.empty[B]}
<强>演示强>
这是一个包含所有必要类型定义的完整可运行示例:
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))
输出:
None
Some(Main$$anon$1$B@5fdef03a)
None
Some(Main$$anon$1$B@48cf768c)
为什么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)
}
语法可以像这样使用:
val optStr: Option[String] = Some("hello")
val reversed = ifNone(optStr) {
Some("makeB")
} otherwise {
str => None
}
更重要的是,如果在过去半个世纪发明的每种编程语言的每一个介绍的第一页上都提到了这种语法,那么ifNone-otherwise
解决方案(即fold
) ,对大多数人来说看起来更自然。
实际上,Option.fold
方法是Option[T]
类型的消除器:只要我们有Option[T]
并希望获得A
在其中,最明显的预期应该是fold(a)(b)
a: A
和b: T => A
。与使用if-else
- 语法(仅仅是惯例)对布尔值进行特殊处理相比,fold
方法非常基础,必须在那里可以从第一原则中得出。
答案 2 :(得分:1)
我想出了这个定义a.map(_ => None).getOrElse(Some(makeB()))
:
scala> def f[A](a: Option[A]) = a.map(_ => None).getOrElse(Some(makeB()))
f: [A](a: Option[A])Option[makeB]
scala> f(Some(44))
res104: Option[makeB] = None
scala> f(None)
res105: Option[makeB] = Some(makeB())