所以,我一直在阅读this article关于 LiftWeb 中 Box 的使用,这似乎是官方文档的一部分,因为它通过源代码注释链接。 我的问题是,为什么 Box/Failure 比实际编码时没有 null 并抛出异常更好,该异常将在顶层被捕获并转换为适当的错误代码/消息。所以而不是
case "user" :: "info" :: _ XmlGet _ =>
for {
id <- S.param("id") ?~ "id param missing" ~> 401
u <- User.find(id) ?~ "User not found"
} yield u.toXml
为什么不
case "user" :: "info" :: _ XmlGet _ => User.find(S.param("id").openOrThrow(
new IllegalArgumentException("idParamMissing"))).toXml
并且让User.find
抛出类似NotFoundException
最佳答案
假设您有一个方法执行某些可能会失败的操作,例如获取网页。
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
}
}
现在我们的逻辑与错误处理代码混合在一起。
将其与以下内容进行比较:
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
使用Option
或Box
(或Either
或scalaz'Validation
)让您有更多的决定权何时处理问题比抛出异常更重要。
除了异常(exception)情况,您只能遍历堆栈并将其捕获为那里的某个点。如果您将故障编码在类型中,您可以随身携带它,只要您愿意,并在您认为最合适的情况下处理它。
关于scala - 为什么在 LiftWeb/Scala 中使用 Box/Option 而不是 Exception?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8329311/