在到达第一个None时如何停止构建Option [Collection]? [英] How do you stop building an Option[Collection] upon reaching the first None?

查看:96
本文介绍了在到达第一个None时如何停止构建Option [Collection]?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

When building up a collection inside an Option, each attempt to make the next member of the collection might fail, making the collection as a whole a failure, too. Upon the first failure to make a member, I'd like to give up immediately and return None for the whole collection. What is an idiomatic way to do this in Scala?

这是我想出的一种方法:

Here's one approach I've come up with:

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返回包含Parts集合的Some,所有这些保证都是有效的.空的收藏集就可以了.

In other words, if any call to findPartByName returns None, allParts returns None. Otherwise, allParts returns a Some containing a collection of Parts, all of which are guaranteed to be valid. An empty collection is OK.

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

The above has the advantage that it stops calling findPartByName after the first failure. But the foldLeft still iterates once for each name, regardless.

这是一个在findPartByName返回None时立即退出的版本:

Here's a version that bails out as soon as findPartByName returns 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)我觉得Scala早已不赞成return了, (c)似乎没有人对我特别清楚.

I currently find the second version more readable, but (a) what seems most readable is likely to change as I get more experience with Scala, (b) I get the impression that early return is frowned upon in Scala, and (c) neither one seems to make what's going on especially obvious to me.

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

The combination of "all-or-nothing" and "give up on the first failure" seems like such a basic programming concept, I figure there must be a common Scala or functional idiom to express it.

推荐答案

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

The return in your code is actually a couple levels deep in anonymous functions. As a result, it must be implemented by throwing an exception which is caught in the outer function. This isn't efficient or pretty, hence the frowning.

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

It is easiest and most efficient to write this with a while loop and an 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循环.

Because we don't know what kind of Seq names is, we must create an iterator to loop over it efficiently rather than using tail or indexes. The while loop can be replaced with a tail-recursive inner function, but with the iterator a while loop is clearer.

这篇关于在到达第一个None时如何停止构建Option [Collection]?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆