在中建立集合时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
return的调用None
,则allParts
return None
。否则,allParts
返回一个Some
包含的集合的Parts
,所有这些保证都有效。空集合是可以的。
上面的优点是它findPartByName
在第一次失败后就停止了调用。但是foldLeft
无论如何,仍然为每个名称重复一次。
这是一个会在findPartByName
返回a时立即退出的版本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)我觉得return
Scala早已不受欢迎,并且(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
所以我们必须创建一个迭代器来高效地对其进行循环,而不是使用tail
或索引。while循环可以用尾递归内部函数代替,但是使用迭代器,while
循环更清晰。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句