重复函数调用,直到我们';将在Scala中获取非空选项结果
Scala中的一个非常新的问题-如何在Scala中执行“重复函数直到返回的内容符合我的标准” 假设我有一个函数,我想调用它直到它返回结果,例如,定义如下:重复函数调用,直到我们';将在Scala中获取非空选项结果,scala,loops,Scala,Loops,Scala中的一个非常新的问题-如何在Scala中执行“重复函数直到返回的内容符合我的标准” 假设我有一个函数,我想调用它直到它返回结果,例如,定义如下: def tryToGetResult: Option[MysteriousResult] 我想出了这个解决方案,但我真的觉得它很难看: 或者,相当丑陋: var res: Option[MysteriousResult] = None while (res.isEmpty) { res = tryToGetResult } doSome
def tryToGetResult: Option[MysteriousResult]
我想出了这个解决方案,但我真的觉得它很难看:
或者,相当丑陋:
var res: Option[MysteriousResult] = None
while (res.isEmpty) {
res = tryToGetResult
}
doSomethingWith(res.get)
我真的觉得有一种解决方案没有var
,也不需要手动检查选项是否为空
相比之下,我看到的Java替代方案在这里似乎更干净:
MysteriousResult tryToGetResult(); // returns null if no result yet
MysteriousResult res;
while ((res = tryToGetResult()) == null);
doSomethingWith(res);
雪上加霜的是,如果我们不需要doSomethingWith(res)
并且只需要从这个函数返回它,Scala vs Java看起来是这样的:
def tryToGetResult: Option[MysteriousResult]
斯卡拉
JAVA
像这样的副作用让我有点内疚,但是这个怎么样
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
您可能希望为lookupuntidefined
提供一个附加参数,以便在从未定义f的情况下它最终可以停止。您可以使用Stream
的连续方法来精确执行以下操作:
val res = Stream.continually(tryToGetResult).flatMap(_.toStream).head
或者(可能更清楚):
这种方法相对于显式递归(除了简洁)的一个优点是,它更容易修补。比如说,我们决定,我们只想得到一千次结果。如果在此之前出现一个值,我们希望它被包装成Some
,否则我们希望它是None
。我们只需在上面的代码中添加几个字符:
Stream.continually(tryToGetResult).take(1000).flatMap(_.toStream).headOption
我们有我们想要的。(请注意,流
是惰性的,因此即使有take(1000)
,如果在三次调用tryToGetResult
后出现一个值,它只会被调用三次。)感谢您的建议!您确定尾部递归优化会接受此递归吗?从Erlang的角度来看,它需要在调用堆栈中存储每个None
实例。如果它不tailrec
可优化,REPL就会发出警告。在没有匹配的情况下,将有更干净的方法来实现这一点,但遗憾的是,这些方法不可优化。(忽略@PrecogIO在此发现的tailrec
non-warning bug)从技术上讲,它会产生额外的对象,并可能产生一个巨大的None
s列表,如果我们尝试无数次得到结果,不是吗?是的,这比我的解决方案要好得多,在迭代器
上有一个几乎相同的连续
,如果这是一个问题,它不会保留其结果。
val res = Stream.continually(tryToGetResult).flatMap(_.toStream).head
val res = Stream.continually(tryToGetResult).dropWhile(!_.isDefined).head
Stream.continually(tryToGetResult).take(1000).flatMap(_.toStream).headOption