【问题标题】:Scala: is Either the only Option?Scala:是否是唯一的选择?
【发布时间】:2012-07-15 00:25:21
【问题描述】:

关于潜在的运行时故障,例如数据库查询,似乎必须使用某种形式的Either[String, Option[T]] 才能准确捕获以下结果:

  1. 一些(找到记录)
  2. 无(未找到记录)
  3. SQL 异常

选项根本没有足够的选项。

我想我需要深入研究 scalaz,但现在它是直接的,除非我在上面遗漏了一些东西。

我的 DAO 实现让自己陷入了困境,只使用 Either 进行写入操作,但现在我看到一些 Either 写入依赖于 Option 读取(例如,检查新用户注册时是否存在电子邮件),这非常糟糕赌一把。

在我全力以赴之前,有没有人有替代解决方案来处理成功/失败/异常的运行时三重奏?

【问题讨论】:

  • 既然记录是可能的,Either[String, List[T]] 会更合适,不是吗?
  • 取决于,我需要处理 Option[T] 和 List[T] 或 Option[List[T]]。现在我对写入操作执行 Either[String, SuccessType],除非我听到其他情况,否则对读取操作执行相同操作
  • @virtualeyes 不,你真的不需要处理所有这些。你说要么有一些记录,没有记录,要么有例外,对吗?那么 Some records 可以是一个非空的记录列表,No records 可以是一个空的记录列表,Exception 和往常一样是两者的左边部分。
  • @DanBurton 是的,这就是我所说的 x,y,z 的意思, Either 或 Option 处理程序将查询结果转换为预期类型;即,如果我说 option[List[Foo]](query) 或 option[Foo](query),我将相应地返回包含 Some 或 None 结果的 Option。切换到 Either-only 查询结果当然需要更多的工作(必须通过结果折叠/映射或 .isRight/.right,或 for{ x

标签: scala error-handling either scala-option


【解决方案1】:

从奇妙的lift 框架中尝试Box。它提供了您想要的。

有关详细信息,请参阅this wiki(以及顶部的链接)。好在lift项目被很好的模块化,使用Box的唯一依赖是net.lift-web % lift-common

【讨论】:

  • +1 谢谢,Box 和 Either[Fail, Option[T]] 有什么区别?大概 Box 更容易使用......
  • 用 Box 你写的更少:D。 Box 是 Monad,因此可以方便地检索三种可能状态中的任何一种或与其他框组合。看看 Box 是如何运作的你可以从the cheatsheet开始
  • 很好的链接,可惜作者还没有写出他在 Box 上提到的文章,以供理解。我在 for{...} 查询事务块上使用了 Either Right 投影,这是一个很棒的保障。对 Box 做同样的事情会很好......
  • Box 实现的一个问题是与 Option 之间的隐式转换。如果将失败信息转换为用于其他 API 的选项,然后再返回到 Box,您最终可能会丢失失败信息而没有意识到。
【解决方案2】:

Option[T] 用于records foundno records found 情况,在 SQLException 情况下抛出异常。

只需将异常包装在您自己的异常类型中,例如PersistenceException,这样您就不会有泄漏的抽象。

我们这样做是因为我们不能也不想从意外的数据库异常中恢复。异常被顶级捕获,我们的网络服务在这种情况下返回500 Internal server error

在我们想要恢复的情况下,我们使用来自 scalaz 的 Validation,这很像 Lift 的 Box

【讨论】:

  • +1,正在考虑让异常冒泡并让 Web 服务器生成 500...但是 Box、Validation 或 Either[Fail, Option[T]] 提供了对实际内容的更多控制出错了,更不用说通过 for{...} 块进行事务查询了,这是 Option 结果类型无法做到的。
【解决方案3】:

这是我修改后的方法

保留返回查询写入操作(对于我们想要回滚以了解左结果的事务块很有用)。

但是,对于返回查询读取的选项,我没有用 None 吞下异常(并记录它),而是创建了一个 500 错误屏幕,让异常冒泡。

在处理诸如查询异常之类的运行时故障时,为什么不默认使用 Either 结果类型?使用 Option[T] 读取比使用 Either[Why-Fail, Option[T]] 更方便一些,您必须折叠/映射才能到达 T。离开 Either 来编写操作可以简化事情(更重要的是所以鉴于这就是应用程序当前的设置方式,不需要重构 ;-))

唯一需要的其他更改是针对 AJAX 请求。我们不是在 AJAX 状态 div 容器中显示整个 500 错误页面响应,而是检查状态类型并相应地显示 500 错误消息。

if(data.status == 500) 
  $('#status > div').html("an error occurred, please try again")

可能会在发送响应之前在服务器端进行 isAjax 检查;在这种情况下,我只能发回状态 + 消息而不是错误页面本身。

【讨论】:

    猜你喜欢
    • 2014-10-10
    • 2013-04-04
    • 1970-01-01
    • 2012-12-16
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    • 1970-01-01
    相关资源
    最近更新 更多