重复函数调用,直到我们在Scala中得到非空的Option结果

时间:2012-11-22 00:59:43

标签: scala loops

Scala中的一个非常新手的问题 - 如何在Scala中执行“重复功能直到返回某些内容符合我的标准”?

鉴于我有一个函数,我想调用它直到它返回结果,例如,定义如下:

def tryToGetResult: Option[MysteriousResult]

我已经提出了这个解决方案,但我真的觉得 丑陋:

var res: Option[MysteriousResult] = None
do {
  res = tryToGetResult
} while (res.isEmpty)
doSomethingWith(res.get)

或者,等同于丑陋:

var res: Option[MysteriousResult] = None
while (res.isEmpty) {
  res = tryToGetResult
}
doSomethingWith(res.get)

我真的觉得有一个没有var的解决方案,并且没有那么麻烦手动检查Option是否为空。

为了比较,我看到的Java替代方案在这里看起来更清晰:

MysteriousResult tryToGetResult(); // returns null if no result yet

MysteriousResult res;
while ((res = tryToGetResult()) == null);
doSomethingWith(res);

如果我们不需要doSomethingWith(res)并且我们只需要从此函数返回它,那么Scala vs Java就是这样:

Scala的

def getResult: MysteriousResult = {
  var res: Option[MysteriousResult] = None
  do {
    res = tryToGetResult
  } while (res.isEmpty)
  res.get
}

爪哇

MysteriousResult getResult() {
    while (true) {
        MysteriousResult res = tryToGetResult();
        if (res != null)  return res;
    }
}

2 个答案:

答案 0 :(得分:14)

您可以使用Stream的{​​{1}}方法来做到这一点:

continually

或(可能更清楚):

val res = Stream.continually(tryToGetResult).flatMap(_.toStream).head

这种方法优于显式递归(除了简洁之外)的一个优点是修补它更容易。比如说我们决定我们只想尝试获得结果一千次。如果某个值在此之前出现,我们希望它包含在val res = Stream.continually(tryToGetResult).dropWhile(!_.isDefined).head 中,如果不是,我们需要Some。我们只需在上面的代码中添加几个字符:

None

我们有我们想要的东西。 (请注意,Stream.continually(tryToGetResult).take(1000).flatMap(_.toStream).headOption 是懒惰的,所以即使Stream存在,如果在三次调用take(1000)后值出现,则只会调用三次。)

答案 1 :(得分:7)

执行这样的副作用会让我内心消失,但是这个怎么样?

scala> import scala.annotation.tailrec
import scala.annotation.tailrec

scala> @tailrec
     | def lookupUntilDefined[A](f: => Option[A]): A = f match {
     |   case Some(a) => a
     |   case None => lookupUntilDefined(f)
     | }
lookupUntilDefined: [A](f: => Option[A])A

然后像这样称呼它

scala> def tryToGetResult(): Option[Int] = Some(10)
tryToGetResult: ()Option[Int]

scala> lookupUntilDefined(tryToGetResult())
res0: Int = 10

您可能希望给lookupUntilDefined一个额外的参数,以便在永远不会定义f的情况下最终停止。