3

我有一些 Scala 代码应该查询网络服务以获取某个令牌,然后将该令牌与预期的令牌进行比较。我想继续查询预期的令牌,直到找到它,或者直到我进行了 N 次不成功的尝试。

以下是如何以 Java 语言方式完成的:

def keepLooking(expectedToken: String, maxTries: Int) {
  var tries = 0
  var token = ""
  do {
    Thread.sleep(tries * 1000) // don't overwhelm the service by calling it too fast!

    token = makeSomeNetworkCall()
    tries += 1
  } while (tries <= maxTries && token != expectedToken)
}

我想在功能上做得更多。我有一个想法:

1.to(maxTries) map { tryNum =>
  Thread.sleep(tryNum - 1 * 1000) // don't overwhelm the service by calling it too fast!
  makeSomeNetworkCall()
} exists (_ == expectedToken)

但这提出了两个问题:

  1. map很懒,所以exists应该短路吧?如果我在第二次通话中找到我的令牌,我不想进行 10 次网络通话。
  2. 有没有更惯用的方法来实现我想要的?
4

4 回答 4

4

回答 1.:

mapRange仅当您将其转换为 a时才懒惰Stream

(1 to 10).toStream map (i => { println(i); i }) exists (_ == 2)
// will print
// 1
// 2
于 2013-11-07T21:57:53.370 回答
3

是否map懒惰,一般来说,取决于集合类型。为了确保它是懒惰的,你可以使用.toStreamor .view(后者不缓存它的结果,所以我通常选择那个)。

除此之外,这对我来说似乎没问题,但它不适用于您实际上需要从响应中获取一些数据的情况(我知道这不是您在这个问题中所需要的,但我正在尝试在这里更一般地考虑)。

于 2013-11-07T21:57:36.457 回答
1

mapon aRange不是懒惰的,所以它会进行maxTries网络调用,然后expectedToken在结果中查找。相反,您可以使用一些惰性结构。一个Iterator,例如:

Iterator.fill(maxTries) {
  makeSomeNetworkCall()
}.exists(_ == expectedToken)
于 2013-11-07T21:58:08.417 回答
1

关于问题 2,您可以创建自己的Stream.

scala>  val keepLooking: Stream[Tuple2[Int, String]] = (0, "a") #:: (1, "aa") #:: keepLooking.tail.map { n => (n._1 + 1, n._2 + "a")}
keepLooking: Stream[(Int, String)] = Stream((0,a), ?)

scala> keepLooking.take(20).find(_._2 == "aaa")
res0: Option[(Int, String)] = Some((2,aaa))

scala> keepLooking.take(20).find(_._2 == "xxx")
res1: Option[(Int, String)] = None

这是一个简化的例子。在您的情况下,您将替换, "a", "aa"and我假设将其返回为. 然后你就可以偷偷拿来用了,看看是否存在。n._2 + "a"makeSomeNetworkCall()tokenStringmaxTriestake(n)findexpectedToken

于 2013-11-07T22:18:48.200 回答