문제
저는 Scala와 Lift를 모두 배우기 위해 Lift에서 작은 문제 관리 시스템을 만들고 있습니다.
프로젝트에 속한 단일 이슈를 표시하는 뷰가 있습니다.데이터를 뷰 템플릿에 바인딩하기 전에 필요한 모든 데이터가 있는지 확인하고 싶기 때문에 구체적으로 다음 사항을 확인하고 싶습니다.
- 프로젝트 ID 매개변수가 제공되었습니다.
- 제공된 프로젝트 ID를 가진 프로젝트가 존재합니다.
- 문제 ID 매개변수가 제공되었습니다.
- 제공된 문제 ID에 문제가 존재합니다.
그리고 이것들은 순서대로 평가되어야 하므로 현재 Scala에 대한 이해를 바탕으로 지금 이 글을 작성한다면 다음과 같이 할 것입니다.
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")
}
}
그래서 이것을 수행하는 더 쉬운 방법이 있는지 궁금합니다.나는 for 표현이 비슷한 것을 수행할 수 있다고 생각합니다.Project.findByID가 Box[프로젝트]를 반환한다는 점에 유의하세요.
해결책
공연에 너무 늦어서 미안하지만 다니엘이 말했듯이 실제로 리프트의 상자를 사용할 수 있고? ~ 이런 일을 할 수 있습니다. 예를 들어:
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이므로 이해를 위해 A 내부에서 완전히 사용할 수 있습니다.
for(projectID <- param("projectID");
if Project.findByID(projectID).isDefined;
issueID <- param("issueID");
if Issue.findByID(issueID).isDefined)
yield ...
오류 메시지가 표시되지 않습니다. 그것에 대해, 나는 내가 언급 한 방법이나 다른 사람들이 좋아하는 방법을 추측하고 있습니다. ~>
, 답을 제공 할 수 있습니다.
저는 Lift에 대해 잘 모르기 때문에 Lift와 관련된 질문에 답변할 수 없습니다.그러나 나는 중첩된 패턴 일치에 의존하지 않고 일련의 확인 후 작동 동작을 작성하는 방법이라는 문제 중 하나를 해결하는 방법을 생각해 냈습니다.
여기서 사용되는 주요 데이터 유형은 Option이지만 귀하의 요구에 맞게 조정하기가 매우 쉬울 것이라고 확신합니다.여기서 우리가 달성하고 싶은 것은 일련의 작업을 수행하는 것입니다.
- 상태를 확인하세요
- 성공하면 계속
- 종료하고 다른 것을 반환
코드는 None을 만나면 일종의 단락을 수행하므로 일련의 작업이 반환될 때 반환 값이 유지됩니다.사용하려면 Option으로 시작한 다음 Option이 Some이면 "ifSome"을 쓰고 Option이 None이면 "ifNone"을 쓰고 시퀀스가 끝날 때까지 계속합니다.시퀀스의 어느 지점에서나 None이 발견되면 "isNone"의 call-by-name 매개변수에서 반환된 옵션이 유지되고 최종 "toOption"이 호출될 때 반환됩니다.실제 옵션 결과를 가져오려면 "toOption"을 사용하세요.
일부 사용 사례는 "main"의 예를 확인하세요.행운을 빌어요!
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)
}
}