我正在为聊天机器人编写HTTPS服务,发现自己正在处理很多期货和期权。通常,如果Option返回None或者Future失败,我想记录异常并将用户重置回到开头。以下是我如何实现这一目标的玩具示例:
(for {
user <- userService.retrieve(userId)
userPet <- Future(user.userPet.get)
_ <- sendTextAsJson(s"You're holding a $userPet!")
} yield {}).recover {
case ex: Exception =>
log.error(ex.toString)
fail
}
这样可以正常工作但是在Future中包装东西感觉有点奇怪,因此它们的异常被吞并并在recover块中处理。包含空的产量块也感觉很奇怪。还有更好的方法吗?
答案 0 :(得分:1)
你基本上做的是使用onSuccess或onFailure来检索期货结果。您也可以尝试尝试。
有一个底层功能的例子。 http://www.scala-lang.org/api/2.9.3/scala/util/Try.html
我可能会建议你这篇文章:http://docs.scala-lang.org/overviews/core/futures.html我无法用几句话总结那里所说的内容。但是,如果您查看右侧的目录,Futures将解释会发生什么以及如何处理它在Excepetions中说明。这是惯用的方式。
答案 1 :(得分:0)
我认为这不是太糟糕,假设userService.retrieve()
首先返回Future。在这种情况下,我个人更倾向于使用地图来使事情变得更加明确:
val futureMsg = userService.retrieve(userId)
.map(user => sendTextAsJson(s"You're holding a ${user.userPet.get}!")
.recover {
case NonFatal(ex) => //Look it up ;)
log.error(ex.toString)
fail
}
你现在有了Future [Unit]来做你想做的事。
答案 2 :(得分:0)
我同意你的观点,这是对理解的尴尬。我就是这样写的:
import scala.util.control.NonFatal
userService.retrieve(userId)
.map(_.userPet.get)
.map(userPet => s"You're holding a $userPet!")
.flatMap(sendTextAsJson)
.recover {
case NonFatal(ex) =>
log.error(ex.toString)
fail
}
答案 3 :(得分:0)
查看sendTextAsJson和失败函数,您似乎希望在将来完成时产生副作用。执行Option.get后我不会使用map,而是查看Futures onComplete方法来处理未来的成功或处理异常抛出。我不确定这种方式和恢复是如何不同虽然如此仔细检查。我确实喜欢@sascha10000链接到scala doc期货。自从我读到这篇文章以来已经很长时间了,但它是我记忆中的一个很好的资源
使用onComplete实现代码的示例:
import scala.concurrent.Future
import scala.util.{Failure, Success}
import scala.concurrent.ExecutionContext.Implicits.global
object UserFuture extends App {
def fail = println("failed")
def sendTextAsJson(message: String): Unit = println(message)
case class User(userPet: Option[String])
object userService {
def userPet = Some("dog")
val someUser = User(userPet)
def retrieve(userId: Int): Future[User] = Future {
someUser
}
}
def getPet(userId: Int): Unit = {
userService.retrieve(userId)
.map(user => user.userPet.get)
.onComplete {
case Success(userPet) => sendTextAsJson(s"You're holding a $userPet!")
case Failure(ex) => println(ex.toString); fail
}
}
getPet(1)
Thread.sleep(10000) // I forgot how to use Await. This is just here to be able to make sure we see some printouts in the console.
}