gpt4 book ai didi

scala - 在到达第一个None时如何停止构建Option [Collection]?

转载 作者:行者123 更新时间:2023-12-04 13:23:02 25 4
gpt4 key购买 nike

Option中构建集合时,每次尝试使集合的下一个成员成为可能会失败,从而使整个集合也失败。第一次未能成为成员时,我想立即放弃并返回整个集合的None。在Scala中,这是一种惯用的方式吗?

这是我想出的一种方法:

def findPartByName(name: String): Option[Part] = . . .

def allParts(names: Seq[String]): Option[Seq[Part]] =
names.foldLeft(Some(Seq.empty): Option[Seq[Part]]) {
(result, name) => result match {
case Some(parts) =>
findPartByName(name) flatMap { part => Some(parts :+ part) }
case None => None
}
}

换句话说,如果对 findPartByName的任何调用返回 None,则 allParts返回 None。否则, allParts返回一个 Some,其中包含 Parts的集合,所有这些保证有效。空集合是可以的。

上面的优点是它在第一次失败后停止调用 findPartByName。但是,无论如何, foldLeft仍会为每个名称迭代一次。

这是一个在 findPartByName返回 None时立即退出的版本:
def allParts2(names: Seq[String]): Option[Seq[Part]] = Some(
for (name <- names) yield findPartByName(name) match {
case Some(part) => part
case None => return None
}
)

我目前发现第二个版本更易读,但是(a)随着我对Scala的了解越来越多,似乎最易读的内容可能会发生变化;(b)我觉得Scala中不赞成早期的 return,并且(c)两者均没有似乎使发生的事情对我尤为明显。

“要么全有要么全无”和“放弃第一个失败”的组合看起来像是一个基本的编程概念,我认为必须有一个通用的Scala或函数用语来表达它。

最佳答案

您的代码中的return实际上在匿名函数中有几个层次。结果,必须通过抛出外部函数中捕获的异常来实现它。这不是有效的或漂亮的,因此皱着眉头。

while循环和Iterator编写此代码最简单,最有效。

def allParts3(names: Seq[String]): Option[Seq[Part]] = {
val iterator = names.iterator
var accum = List.empty[Part]
while (iterator.hasNext) {
findPartByName(iterator.next) match {
case Some(part) => accum +:= part
case None => return None
}
}
Some(accum.reverse)
}

因为我们不知道 Seq是哪种类型,所以我们必须创建一个迭代器来高效地对其进行循环,而不是使用 names或索引。 while循环可以用尾部递归内部函数代替,但是使用迭代器, tail循环更加清晰。

关于scala - 在到达第一个None时如何停止构建Option [Collection]?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23914713/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com