题
我在做一个小问题管理体系在提升学习这两个服务台。
我有一个图显示一个单一的问题属于一个项目。之前我结合的数据的视图模板,我要检查我们所需要的数据,因此,我希望以具体检查:
- 一个项目ID param已经提供的
- 项目的存在与供给项目编号
- 一个问题ID param已经提供的
- 一个问题的存在与供给问题ID
和这些需要进行评估的顺序,因此如果我把它写在我的当前的理解,卡拉,我会做到以下几点:
class Project {
def findByID(xhtml:NodeSeq): NodeSeq =
param("projectID") match {
case Full(projectID) =>
Project.findByID(projectID) match {
case Full(projectID) =>
param("issueID") match {
....
}
case _ => Text("Project does not exist")
}
case _ => Text("projectIDNotSupplied")
}
}
所以我想知道,如果有一个更简单的方式来执行这个吗?我认为,对表达方式可能能够进行类似的东西。要知道这一项目。findByID返回一个箱[项目].
解决方案
对不起,我这么晚的演出,但作为丹尼尔说你确实可以使用电梯的框并?~ 要做到这样的事情。例如:
import net.liftweb.util.Box
import net.liftweb.util.Box._
class Project {
def findByID(xhtml:NodeSeq): NodeSeq =
(for {
projectID <- param("projectID") ?~ "projectIDNotSupplied"
project <- Project.findById(projectID) ?~ "Project does not exist"
issueID <- param("issueID") ?~ "issueIDNotSupplied"
...
} yield {
...
}) match {
case Full(n) => n
case Failure(msg, _, _) => Text(msg)
case _ => Text("fail")
}
}
什么?~ 不是打开一个空的盒子变成一个失败框给串的错误信息,但并没有一个全面(成功)框。所以返回的价值findByID将是完整的,如果一切成功,或故障(与所给的错误消息)。如果你想要的故障链,那么使用吗?~!代替。
其他提示
我不知道电梯,但有几件事情我已经看到在它的实施。他们中的一个是失败的方法: ?~
和 ?~!
.我不确定究竟是如何一个可能去使用它们,但它似乎是有用的。另一个是 open_!
, ,扔例外情况。
现在,一个框支持地图,flatMap、过滤器和foreach,所以它可以完全使用内部一个用于理解:
for(projectID <- param("projectID");
if Project.findByID(projectID).isDefined;
issueID <- param("issueID");
if Issue.findByID(issueID).isDefined)
yield ...
这不会得到你的错误消息。对于那些,我的猜测的方法,我所提到的,或其他人一样 ~>
, 可能提供答案。
我不知道电梯所以我可以不回答任何提具体问题。我没有,但是,找到了一种方法要解决的一个问题是如何编写一个序列的检查-那么工作的行动,而不诉诸嵌套的模式匹配。
主要数据类型中使用这里的选择,但是我相信它将很容易适应的需要。我们想要完成这里是做一个顺序
- 检查状况
- 继续,如果成功
- 终止,否则返回的东西
代码不是一种短路一次遇到一个没有所以返回的价值是保留当的行动顺序的返回。使用,开始一个选项,然后写入"ifSome"如果选项是一些和"ifNone"如果选择是没有的,一直持续到序列完成。如果没有遇到任何一点在序列,选择返回的自称的名参数"isNone"保留和返回时的最终"toOption"。使用"toOption"回的实际选择的结果。
检查出一例,在"主要的"对某些使用情况。祝你好运!
object Options {
class RichOption[A](a: Option[A]) {
def ifSome[B](f: A => Option[B]): RichOption[B] = a match {
case Some(x) => new RichOption(f(x))
case None => this.asInstanceOf[RichOption[B]]
}
def ifNone[B](f: => Option[B]): RichOption[B] = a match {
case Some(_) => this.asInstanceOf[RichOption[B]]
case None => new RichNone(f)
}
def toOption[A] = a
}
class RichNone[A](a: Option[A]) extends RichOption[A](a) {
override def ifSome[B](f: A => Option[B]): RichOption[B] = this.asInstanceOf[RichOption[B]]
override def ifNone[B](f: => Option[B]): RichOption[B] = this.asInstanceOf[RichOption[B]]
}
implicit def option2RichOption[A](a: Option[A]): RichOption[A] = new RichOption(a)
def main(args: Array[String]) {
println(Some("hello") ifSome(s => Some(s.toUpperCase)) toOption) // prints Some(HELLO)
println(Some("hello") ifNone(Some("empty")) toOption) // prints Some(hello)
println(Some("hello") ifSome(s => Some(s.toUpperCase)) ifNone(Some("empty")) toOption) // prints Some(HELLO)
println(Some("hello") ifNone(Some("empty")) ifSome(s => Some(s.toUpperCase)) toOption) // prints Some(HELLO)
println((None: Option[String]) ifSome(s => Some(s.toUpperCase)) toOption) // prints None
println((None: Option[String]) ifNone(Some("empty")) toOption) // prints Some(empty)
println((None: Option[String]) ifSome(s => Some(s.toUpperCase)) ifNone(Some("empty")) toOption) // prints Some(empty)
println((None: Option[String]) ifNone(Some("empty")) ifSome(s => Some(s.toUpperCase)) toOption) // prints Some(empty)
println(Some("hello world") ifSome(s => Some(s.toUpperCase)) ifNone(Some("empty")) ifSome(s => Some(s.length)) ifNone(None) toOption) // prints Some(11)
println(Some("hello world") ifSome(_ => None) ifNone(Some("goodbye world")) ifSome(s => Some(s.length)) ifNone(None) toOption) // prints Some(goodbye world)
println((None: Option[String]) ifSome(s => Some(s.toUpperCase)) ifNone(Some("empty")) ifSome(s => Some(s.length)) ifNone(None) toOption) // prints Some(empty)
println((None: Option[String]) ifSome(_ => None) ifNone(Some("goodbye world")) ifSome(s => Some(s.length)) ifNone(None) toOption) // prints Some(goodbye world)
}
}