我有一些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)
但这提出了两个问题:
map
很懒,所以exists
应该短路吧?如果我在第二次通话中找到我的令牌,我不想拨打10个网络电话。答案 0 :(得分:4)
回答1:
如果您将map
转换为Range
,则 Stream
只是懒惰:
(1 to 10).toStream map (i => { println(i); i }) exists (_ == 2)
// will print
// 1
// 2
答案 1 :(得分:3)
map
是否懒惰,通常取决于集合类型。为了确保它是懒惰的,你可以使用.toStream
或.view
(后者不会缓存其结果,所以我通常选择这样做。)
除此之外,对我来说似乎没问题,但是对于你真的需要从响应中获取一些数据的情况它不会起作用(我知道这不是你在这个问题中需要的,但是我'我试图在这里更广泛地思考。)
答案 2 :(得分:1)
map
上的{p> Range
不是懒惰的,因此会进行maxTries
个网络呼叫,然后在结果中查找expectedToken
。相反,你可以使用一些懒惰的结构。一个Iterator
,例如:
Iterator.fill(maxTries) {
makeSomeNetworkCall()
}.exists(_ == expectedToken)
答案 3 :(得分: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"
和n._2 + "a"
替换为makeSomeNetworkCall()
我假设将token
作为String
返回。然后,您可以懒惰地使用maxTries
取take(n)
并使用find
查看expectedToken
是否存在。