gpt4 book ai didi

scala - 是否每个 Scala Future 最终都必须调用 Await.result

转载 作者:行者123 更新时间:2023-12-03 22:54:08 27 4
gpt4 key购买 nike

我正在尝试学习 Scala future 。正如标题所暗示的,在我看来 Await.result最终必须在程序中的某个时刻调用以获取提取到 Scala 字段中的 future 的值。到目前为止,这是我的代码。我在这里查询任意 uri 并将其映射到名为 Address 的案例类假设这个 Address case 类只有一个字段,final_balance .

  case class Address(final_balance:Double) 
def getAddress(bitcoinAddress: String)(format: DataFormat): Future[Address] = {

val uri: String = "http://example.com"
val response: Future[HttpResponse] = (IO(Http) ? HttpRequest(GET, Uri(uri))).mapTo[HttpResponse]

implicit val addressJsonFormat = AddressJsonProtocol.addressFormat
val address: Future[Address] = response.flatMap { x =>
x match {
case HttpResponse(_, entity, _, _) =>
Future(entity.asString.parseJson.convertTo[Address])
}
}
address
}

def getFinalBalance(address: String): Double = {
val futureAddress: Future[Address] = QueryAddress.getAddress(address)(Json)
val finalBalance:Future[Double] = for { a <- futureAddress } yield a.final_balance

//block until the result can be determined
Await.result(finalBalance, 15.second)


}

这不正确吗?

最佳答案

这不是从 Future[A] 获取或执行某些潜在值/结果的唯一方法。这里有一些其他的考虑方法:

组合器

future 组合器的重点是能够将 future 组合在一起,然后才能从最终 future 中拉出基础。尽可能推迟通常是一个好主意。

有一个recover组合器,它将允许您做一些事情来处理发生的异常:

f1 recover {
case e: ApiException => ...do something...
}

有一个 fallbackTo组合器也是:
f1 fallbackTo f2 // (if result of `f1` is failure case, then execute `f2`)

现在,如果您希望完成的第一个 future 成为返回的结果,您可以使用 either combinator 虽然它具有有趣的特性,因此请阅读文档并在 REPL 中使用它以更好地理解它:
f1 either f2

还有 filter , foreach ,以及两个最明显的 map , 和 flatmap .您可能想要使用的另一个组合器是 zip这会将两个 future 的结果“压缩”为一个元组,然后您可以 apply到数据/值构造函数。

还有 andThen可以这样使用:
f1 andThen f2 // this defines order of execution (f1 and then f2 in this case)

映射(最常用的组合器 IME)

是的,这不会得到潜在的值(value),但它可以对值(value)做一些事情:
val fUsers: Future[Int] = future {
api.getConcurrentUsers
}

val fShouldCelebrate: Future[Boolean] = fUsers map { userCount =>
(userCount >= 1000000)
}

// pass fShouldCelebrate around and use a method for extracting the underlying out when
// absolutely needed.

通过回调

我不一定推荐这种方法,但它是您可以用 Future[A] 的结果做某事的方法之一。 .

一个例子是:
import scala.util.{Success, Failure}

// Not sure what a Response type is...but use your imagination :)
val response: Response = ???
val f: Future[List[String]] = future {
db.getRecentPosts
}

f onComplete {
case Success(posts) => for (p <- posts) response.render(p)
case Failure(t) => response.error("An error has occured: " + t.getMessage)
}

或者,我们可以将行为分为成功案例和失败案例:
import scala.util.{Success, Failure}

// Not sure what a Response type is...but use your imagination :)
val response: Response = ???
val f: Future[List[String]] = future {
db.getRecentPosts
}

f onSuccess {
case posts => for (p <- posts) response.render(p)
}

f onFailure {
case t => response.error("An error has occured: " + t.getMessage)
}

用于理解和预测

有时你有依赖的 future 值,让我们看看这个例子:
val ticker: String = "XYZA" // hopefully not a real ticker
val f1: Future[TickerQuote] = future { exchange1.getQuote(ticker) }
val f2: Future[TickerQuote] = future { exchange2.getQuote(ticker) }

val trade = for {
q1 <- f1
q2 <- f2
if (q1 < q2)
} yield exchange1.buy(ticker, 100)

// obviously this is silly but hopefully you get the point?

f1f2失败那么你可以使用失败的投影,像这样:
val f1: Future[Int] = future {
throw new RuntimeException("whoops")
}
for (t <- f1.failed) response.error(t)

Await ing

我们有 Await.resultAwait.ready阻止调用以从 Future 中获取基础值。

我不建议将自己限制在 Future[A] s。你应该看看 Scalaz 的 Task[A]构造,我发现它更灵活、更直观(对我来说)和可组合。

延伸阅读
  • SIP-14 - Futures and Promises (注意:我根本没有涵盖 promise ,只是已经使用了 Scalaz Concurrent 的 Task[A];)我一点也不固执己见。)
  • The Neophytes Guide to Scala Part 9: Promises & Futures in Practice
  • Scalaz Stream使用 scalaz.concurrent.Task
  • 关于scala - 是否每个 Scala Future 最终都必须调用 Await.result,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26620971/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com