2011-11-30 1 views
2

그래서 LiftWeb의 Box 사용에 관해서는 this article을 읽었습니다. 공식 문서의 일부로 보이기 때문에 소스 코드 주석을 통해 링크되어 있습니다. 제 질문은 Box/Failure가 실제로 null을 코딩하지 않고 최상위 레벨에서 잡히고 적절한 오류 코드/메시지로 변환되는 Exception을 던지기보다 적합한 이유입니다. 당신이 예외가 발생하는 경우 그래서 그 대신왜 LiftWeb/Scala에서 예외 대신 상자/옵션이 필요합니까?

case "user" :: "info" :: _ XmlGet _ => 
    for { 
    id <- S.param("id") ?~ "id param missing" ~> 401 
    u <- User.find(id) ?~ "User not found" 
    } yield u.toXml 

의 이유 NotFoundException

+0

좋은 질문입니다. 나는 그것에 대해 생각 해본 적이 없다 ... – drozzy

+0

@drozzy 메일 링리스트에서 답변을 읽었는지 확인하십시오. http://goo.gl/5Lv7V –

답변

2

잠재적으로 실패 할 수있는 일부 작업 (예 : 웹 페이지 가져 오기)을 수행하는 방법이 있다고 상상해보십시오. 당신이 그것을 사용하려는 경우

def getUrl(url: String): NodeSeq = { 
    val page = // ... 
    // ... 
    if (failure) throw new PageNotFoundException() 
    page 
} 

, 당신은 상황에 따라

val node = try { 
    getUrl(someUrl) 
} catch { 
    case PageNotFoundException => NodeSeq.Empty 
} 

또는 유사 할 필요가있다. 그래도 그래도 괜찮은 것 같습니다. 그러나 이제 URL 모음에 대해이 작업을 수행하려고한다고 가정합니다.

val urls = Seq(url1, ...) 
val nodeseqs: Seq[NodeSeq] = try { 
    urls.map(getUrl) 
} catch { 
    case PageNotFoundException => Seq.Empty 
} 

좋아, 이렇게하면 페이지 중 하나를로드 할 수 없을 때마다 빈 시퀀스가 ​​반환됩니다. 우리가 최대한 많은 것을 받고 싶다면 어떻게해야할까요?

val urls = Seq(url1, ...) 
val nodeseqs: Seq[NodeSeq] = urls.map { url => 
    try { 
    getUrl(url) 
    } catch { 
    case PageNotFoundException => NodeSeq.Empty 
    } 
} 

이제 로직이 오류 처리 코드와 혼합됩니다.

는 다음이 비교 :

Option 또는 Box (또는 Either 또는 scalaz ' Validation)를 사용하여
def getUrl(url: String): Box[NodeSeq] = { 
    val page = // ... 
    // ... 
    if (failure) Failure("Not found") 
    else Full(page) 
} 

val urls = Seq(url1, ...) 
val nodeseqs: Seq[Box[NodeSeq]] = urls.map(getUrl(url)).filter(_.isDefined) 
// or even 
val trueNodeseqs: Seq[NodeSeq] = urls.map(getUrl(url)).flatten 

적 예외를 수 던지는 것보다 문제를 처리 할 때 결정을 통해 당신에게 방법으로 더 많은 전력을 제공합니다.

예외가 있으면 스택을 가로 질러서 그곳에서 어떤 지점으로 잡을 수 있습니다. 유형 내에서 오류를 인코딩하는 경우 가장 적절하다고 판단되는 상황에서 원하는만큼 오류를 처리하고 처리 할 수 ​​있습니다.

+0

모두가 나에게 당신이 설명하는 상황으로 돌아가는 답변을 계속 제공합니다. 실제로, 거의 발생하지 않는 API를 작성할 때. –

2

같은 User.find 던져 뭔가를하지

case "user" :: "info" :: _ XmlGet _ => User.find(S.param("id").openOrThrow(
    new IllegalArgumentException("idParamMissing"))).toXml 

하고, 당신이 할 수있는 유일한 방법은 그것을 잡을 것입니다. 따라서 페이지의 두 부분에서 예외가 발생하면 두 번째 페이지로 이동하지 않습니다. 페이지의 한 부분이 FailureBox을 반환하고 두 번째 부분이 첫 번째 부분의 반환 값을 필요로하지 않으면 두 가지 모두를 볼 수 있습니다. 보다 일반적으로, Box은 유용한 API를 가지고있다.

+4

그래, 그 이유 중 하나 인 것 같습니다. 비록 하나의 실패가 당신을 멈추게해야하는 상황을 오히려 생각하고 있었지만. David Pollak의 메일 링리스트에서 좋은 답변을 얻었습니다. http://goo.gl/5Lv7V –