从Scala未来完成返回值

时间:2016-10-10 13:08:21

标签: scala functional-programming slick future

来自Java背景,我一直在尝试自学Scala一段时间。作为其中的一部分,我正在做一个小型宠物项目,它公开了一个HTTP端点,它将registration number的车辆保存在owner并返回状态。

为了提供更多上下文,我使用Slick作为FRM,它以异步方式执行数据库操作并返回Future。 基于此Future的输出,我想设置status变量以返回给客户端。

这里是代码

def addVehicleOwner(vehicle: Vehicle): String = {
    var status = ""
    val addFuture = db.run((vehicles returning vehicles.map(_.id)) += vehicle)
    addFuture onComplete {
      case Success(id) => {
        BotLogger.info(LOGTAG, s"Vehicle registered at $id ")
        status = String.format("Registration number - '%s' mapped to owner '%s' successfully", vehicle.registration,
          vehicle.owner)
        println(s"status inside success $status") //--------- (1)
      }
      case Failure(e: SQLException) if e.getMessage.contains("SQLITE_CONSTRAINT") => {
        status = updateVehicleOwner(vehicle)
        BotLogger.info(LOGTAG, s"Updated owner='${vehicle.owner}' for '${vehicle.registration}'")
      }
      case Failure(e) => {
        BotLogger.error(LOGTAG, e)
        status = "Sorry, unable to add now!"
      }
    }
    exec(addFuture)
    println(s"Status=$status") //--------- (2)
    status
  }

  // Helper method for running a query in this example file:
  def exec[T](sqlFuture: Future[T]):T = Await.result(sqlFuture, 1 seconds)

这在Java中相当简单。使用Scala,我面临以下问题:

  • 期望值打印在(1),但(2)始终打印空字符串,同样是返回的方法。有人可以解释原因吗?
  • 我甚至尝试将var status标记为@volatile var status,它仍然评估为空字符串。

  • 我知道,上面不是功能性的做事方式,因为我正在静音状态。为这种情况编写代码的简洁方法是什么。

  • 我发现的几乎所有示例都描述了如何通过执行Success来映射Failure或处理println的结果。我想做更多的事情。
  • 我可以参考哪些小项目的好参考?特别是,遵循TDD。

1 个答案:

答案 0 :(得分:4)

而不是依赖status来完成闭包,你可以recover覆盖处理异常的Future[T],并且总是返回你想要的结果。这是利用Scala中表达式的本质:

val addFuture = 
  db.run((vehicles returning vehicles.map(_.id)) += vehicle)
    .recover {
      case e: SQLException if e.getMessage.contains("SQLITE_CONSTRAINT") => {
        val status = updateVehicleOwner(vehicle)
        BotLogger.info(
          LOGTAG, 
          s"Updated owner='${vehicle.owner}' for '${vehicle.registration}'"
        )
        status
      }
      case e => {
        BotLogger.error(LOGTAG, e)
        val status = "Sorry, unable to add now!"
        status
      }
    }

val result: String = exec(addFuture)
println(s"Status = $result")
result

请注意,Await.result不应在任何生产环境中使用,因为它Future上的同步阻止,这与您实际需要的完全相反。如果您已经使用Future委派工作,则希望它以异步方式完成。我假设您的exec方法仅用于测试目的。