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就是这样:
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;
}
}
答案 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的情况下最终停止。