Scala中的一个非常新手的问题 - 如何在Scala中执行"重复功能,直到返回某些内容符合我的标准"?
鉴于我有一个函数,我想调用它,直到它返回结果,例如,定义如下:
def tryToGetResult: Option[MysteriousResult]
Run Code Online (Sandbox Code Playgroud)
我想出了这个解决方案,但我真的觉得这是丑陋的:
var res: Option[MysteriousResult] = None
do {
res = tryToGetResult
} while (res.isEmpty)
doSomethingWith(res.get)
Run Code Online (Sandbox Code Playgroud)
或者,相当丑陋:
var res: Option[MysteriousResult] = None
while (res.isEmpty) {
res = tryToGetResult
}
doSomethingWith(res.get)
Run Code Online (Sandbox Code Playgroud)
我真的觉得有一个解决方案,没有var
和没有这么多麻烦手动检查是否Option
是空的.
为了比较,我看到的Java替代方案在这里看起来更清晰:
MysteriousResult tryToGetResult(); // returns null if no result yet
MysteriousResult res;
while ((res = tryToGetResult()) == null);
doSomethingWith(res);
Run Code Online (Sandbox Code Playgroud)
为了增加对伤害的侮辱,如果我们不需要doSomethingWith(res)
并且我们只需要从这个函数返回它,Scala vs Java看起来像这样:
def getResult: MysteriousResult = {
var res: Option[MysteriousResult] = None
do {
res = tryToGetResult
} while (res.isEmpty)
res.get
}
Run Code Online (Sandbox Code Playgroud)
MysteriousResult getResult() {
while (true) {
MysteriousResult res = tryToGetResult();
if (res != null) return res;
}
}
Run Code Online (Sandbox Code Playgroud)
Tra*_*own 15
您可以使用Stream
的continually
方法来做到这一点:
val res = Stream.continually(tryToGetResult).flatMap(_.toStream).head
Run Code Online (Sandbox Code Playgroud)
或者(可能更清楚):
val res = Stream.continually(tryToGetResult).dropWhile(!_.isDefined).head
Run Code Online (Sandbox Code Playgroud)
这种方法优于显式递归(除了简洁之外)的一个优点是修补它更容易.比如说我们决定我们只想尝试获得结果一千次.如果一个值在此之前出现,我们希望它包含在a中Some
,如果不是,我们想要一个None
.我们只需在上面的代码中添加几个字符:
Stream.continually(tryToGetResult).take(1000).flatMap(_.toStream).headOption
Run Code Online (Sandbox Code Playgroud)
我们有我们想要的东西.(注意,它Stream
是懒惰的,所以即使take(1000)
它存在,如果在三次调用之后值出现tryToGetResult
,它将只被调用三次.)
像这样表现出副作用会让我内心消失,但是这个怎么样?
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
Run Code Online (Sandbox Code Playgroud)
然后这样称呼它
scala> def tryToGetResult(): Option[Int] = Some(10)
tryToGetResult: ()Option[Int]
scala> lookupUntilDefined(tryToGetResult())
res0: Int = 10
Run Code Online (Sandbox Code Playgroud)
您可能想要提供lookupUntilDefined
一个额外的参数,以便在永远不会定义f的情况下最终停止.