문제

저는 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이지만 귀하의 요구에 맞게 조정하기가 매우 쉬울 것이라고 확신합니다.여기서 우리가 달성하고 싶은 것은 일련의 작업을 수행하는 것입니다.

  1. 상태를 확인하세요
  2. 성공하면 계속
  3. 종료하고 다른 것을 반환

코드는 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)
  }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top