我有许多返回
Option
值的函数,就像这样
case class A()
case class B()
case class C()
def optionA(): Option[A] = None
def optionB(): Option[B] = Some(B())
def optionC(): Option[C] = Some(C())
我想要做的是,我想按顺序运行这些函数,但直到其中一个函数返回带有值(a
Option
)的Some
。然后我想返回该值,而不运行其余的函数。
这是我当前的实现
val res:Option[Any] = Stream(
() => optionA(),
() => optionB(),
() => optionC()
) .map(f => f())
.filter(opt => opt.isDefined)
.head
对于上面的函数实现,这适用于
optionA
和 optionB
,给我一个 Some(B())
,并且它永远不会运行 optionC
,这就是我想要的。
但我想知道是否有更好/简单/替代的实现。
类似
val findFirst = optionA compose optionB compose optionC
的东西?
optionA().orElse(optionB()).orElse(optionC())
如果定义了 orElse
,则
this
将不会计算其参数。
或者,如果您已经在集合/流中拥有选项,您可以这样做
options.find(_.isDefined).flatten
假设您现在拥有
Option
的集合,那么您可以执行以下操作:
coll.foldLeft[Option[Int]](None)(_ orElse _)
这将返回集合中第一个非
None
值
请注意,我明确提到了集合的类型,因为 scala 无法推断
orElse
在没有它的情况下应该做什么...(None
默认情况下是 Option[Any]
类型)
如果你有一个巨大的选项列表,写下来可能会有帮助
coll.view.foldLeft[Option[Int]](None)(_ orElse _)
有几件事需要指出。
isDefined
,如已接受的答案所示。事实上,显式检查 Option
是否为空是一种反模式,因为它与检查 null
没有什么不同,而 Option
的存在正是为了避免这种情况。Seq(None, Some(1), None, Some(2))
.flatten
.headOption // Some(1)
List
的 Option
,或任何长度已知的集合,则上述方法没问题。但是,如果您想通过调用另一个函数来找到第一个非空结果,那么您需要注意一个陷阱。def loop(i: Int): Option[String] =
println(i)
if i == 5 then Some("yes") else None
Iterator
.range(0, 10)
.flatMap(loop)
.nextOption() // Some("yes")
这将打印
0
到 5
。然而:
(0 to 9)
.flatMap(loop)
.headOption // Some("yes")
将打印
0
至 9
。即使值 5
返回非空 Option
,迭代也会继续,直到集合耗尽。
上面的代码是用 Scala 3.3.4 测试的。