从 Scala 未来完成返回值

Returning value from Scala future completion

来自 Java 背景,一段时间以来我一直在尝试自学 Scala。作为其中的一部分,我正在做一个小型宠物项目,该项目公开了一个 HTTP 端点,该端点将车辆的 registration numberowner 和 return 的状态相对应。

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

这里是代码

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,我面临以下问题:

而不是依赖 status 在闭包内部完成,您可以 recoverFuture[T] 上处理异常,如果它们发生,总是 returns你想要的结果。这是利用 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 方法仅用于测试目的。