参考: Scala在 Scala 控制器中
返回关键字处理错误
EDIT3
这是“最终”解决方案,再次感谢 Dan Burton。
def save = Action { implicit request =>
val(orderNum, ip) = (generateOrderNum, request.remoteAddress)
val result = for {
model <- bindForm(form).right // error condition already json'd
transID <- payment.process(model, orderNum) project json
userID <- dao.create(model, ip, orderNum, transID) project json
} yield (userID, transID)
}
然后是 pimp'd Either 项目方法,放置在您的应用程序中的某个位置(在我的情况下,一个隐式特征,即 sbt 根和子项目从以下位置扩展它们的基本包对象:
class EitherProvidesProjection[L1, R](e: Either[L1, R]) {
def project[L1, L2](f: L1 => L2) = e match {
case Left(l:L1) => Left(f(l)).right
case Right(r) => Right(r).right
}
}
@inline implicit final def either2Projection[L,R](e: Either[L,R]) = new EitherProvidesProjection(e)
EDIT2
Evolution,已经从嵌入式返回语句变成了这个密度的小白矮星(感谢@DanBurton,Haskell 流氓;-))
def save = Action { implicit request =>
val(orderNum, ip) = (generateOrderNum, request.remoteAddress)
val result = for {
model <- form.bindFromRequest fold(Left(_), Right(_)) project( (f:Form) => Conflict(f.errorsAsJson) )
transID <- payment.process(model, orderNum) project(Conflict(_:String))
userID <- dao.create(model, ip, orderNum, transID) project(Conflict(_:String))
} yield (userID, transID)
...
}
我已将 Dan 的 onLeft Either 投影作为皮条客添加到 Either,使用上述“项目”方法,该方法允许右偏eitherResult project(left-outcome)
. 基本上,您将失败优先错误作为左派,将成功作为右派,这在将选项结果提供给理解时不起作用(您只会得到一些/无结果)。
我唯一不满意的是必须指定 ; 的类型project(Conflict(param))
。我认为编译器能够从传递给它的 Either 中推断出左条件类型:显然不是。
无论如何,很明显,函数式方法不需要嵌入返回语句,就像我尝试使用 if/else 命令式方法一样。
编辑
功能等价物是:
val bound = form.bindFromRequest
bound fold(
error=> withForm(error),
model=> {
val orderNum = generateOrderNum()
payment.process(model, orderNum) fold (
whyfail=> withForm( bound.withGlobalError(whyfail) ),
transID=> {
val ip = request.headers.get("X-Forwarded-For")
dao.createMember(model, ip, orderNum, transID) fold (
errcode=>
Ok(withForm( bound.withGlobalError(i18n(errcode)) )),
userID=>
// generate pdf, email, redirect with flash success
)}
)}
)
这当然是一个功能强大的代码块,在那里发生了很多事情;但是,我认为相应的带有嵌入式返回的命令式代码不仅同样简洁,而且更容易理解(具有更少的尾随花括号和括号来跟踪的额外好处)
ORIGINAL
发现自己处于紧急情况;希望看到以下方法的替代方法(由于使用 return 关键字和方法上缺少显式类型而不起作用):
def save = Action { implicit request =>
val bound = form.bindFromRequest
if(bound.hasErrors) return Ok(withForm(bound))
val model = bound.get
val orderNum = generateOrderNum()
val transID = processPayment(model, orderNum)
if(transID.isEmpty) return Ok(withForm( bound.withGlobalError(...) ))
val ip = request.headers.get("X-Forwarded-For")
val result = dao.createMember(model, ip, orderNum, transID)
result match {
case Left(_) =>
Ok(withForm( bound.withGlobalError(...) ))
case Right((foo, bar, baz)) =>
// all good: generate pdf, email, redirect with success msg
}
}
}
在这种情况下,我喜欢使用 return 来避免嵌套多个 if/else 块、折叠、匹配或填充空白的非命令式方法。当然,问题在于它不起作用,必须指定显式返回类型,这有其自身的问题,因为我还没有弄清楚如何指定一个满足 Play 魔法工作的类型 - 不,def save: Result
, 不起作用,因为编译器然后抱怨implicit result
现在没有显式类型;-(
无论如何,Play 框架示例提供了 la, la, la, la 快乐的 1-shot-deal fold(error, success) 条件,这在现实世界中并非总是如此™ ;-)
那么上述代码块的惯用等价物(不使用返回)是什么?我假设它会嵌套 if/else、match 或 fold,这有点难看,每个嵌套条件都会缩进。