来自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,我面临以下问题:
我甚至尝试将var status
标记为@volatile var status
,它仍然评估为空字符串。
我知道,上面不是功能性的做事方式,因为我正在静音状态。为这种情况编写代码的简洁方法是什么。
Success
来映射Failure
或处理println
的结果。我想做更多的事情。答案 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
方法仅用于测试目的。