11

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)、この関数から返す必要がある場合、ScalavsJavaは次のようになります。

Scala

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

Java

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

2 に答える 2

15

Streamのメソッドを使用continuallyして、これを正確に行うことができます。

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

または(おそらくもっと明確に):

val res = Stream.continually(tryToGetResult).dropWhile(!_.isDefined).head

(簡潔さを除いて)明示的な再帰に対するこのアプローチの利点の1つは、いじくり回すのがはるかに簡単なことです。たとえば、結果を1000回だけ取得しようと決めたとします。それ以前に値が表示された場合は、それを。でラップする必要がSomeあり、そうでない場合は、をラップする必要がありNoneます。上記のコードにいくつかの文字を追加するだけです。

Stream.continually(tryToGetResult).take(1000).flatMap(_.toStream).headOption

そして、私たちは欲しいものを持っています。Stream(は怠惰であることに注意してください。そのため、take(1000)が存在していても、を3回呼び出した後に値が表示された場合、その値はtryToGetResult3回しか呼び出されません。)

于 2012-11-22T01:51:39.307 に答える
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

lookupUntilDefinedfが定義されていない場合に最終的に停止できるように、追加のパラメーターを指定することをお勧めします。

于 2012-11-22T01:17:17.760 に答える