【问题标题】:How to avoid Option.get and pattern match on None for Option that is always Some?对于始终为 Some 的 Option,如何避免 Option.get 和 None 上的模式匹配?
【发布时间】:2015-01-14 18:56:44
【问题描述】:

我有这段(元)代码处理我要更新的数据库对象T

已知的只有此类对象的ID、检索对象的query 和执行的update

def updateObject(...) : Either[(Int,String),(Int,T)] = {

    T.update(
      query,
      update,
    ) match {

    case 0 => Left(404, "No such object!")
    case _ =>
        T.findOne("id == objectId")
        .map((200, _)) match {
          case Some(result) => Right(result)
          case _ => ???
        }

  }

}

T.update 对满足query 的对象执行更新并返回写入结果,该结果为整数(受更新影响的记录数)。

返回类型为Either[(Int,String),(Int,T)]:

  • Left 是一个具有以下格式的元组:(error_code, error_message)。
  • Right 的格式改为:(status_code, updated_object)。

如果受影响的记录数为 0,则该对象不存在,因此我返回 Left(404,"No such object")

如果对象已更新,我需要获取它(因为我只有它的 id),将它映射到 (Int,T),然后在 Right 中返回它。

问题来了

T.findOne 返回Option[T]

我已经对对象执行了更新,因此它存在并且结果将始终为Some(T)

我知道case _ => ??? 永远不会被调用,但是如果我不把它放进去,编译器会警告我匹配不是详尽的。

有没有更好的方法来处理这个问题(Option 总是保证是Some)?

(我试图避免使用Option.get 方法),而case _ => ??? 似乎是不必要且令人困惑的代码。

【问题讨论】:

  • 似乎有一个极端的情况,即在您更新对象之后,在您再次检索它之前可以将其删除。为什么不针对这种情况使用您自己的另一个错误代码?
  • 我正在这样做,但后来我意识到这是一个“超极端”的边缘情况。以前的代码是:T.findOne("id == objectId").map((200, _)).toRight(500, "Object has been deleted")
  • 您不需要对选项进行匹配。你可以只做 T.findOne("id == objectId").get 如果结果不是 Some 会抛出异常
  • @Matteo Pcini “这不是一个好的模式” - 你能否提供一些参考,为什么它不是
  • @MatteoPacini “这不是一个好的模式”,因为它忽略了选项为 None 的可能性,这正是您想要做的。一般来说,你可以说“这不是一种非常惯用的方式”来将你关于它的“元知识”“保证永远不会”应用于Option。关于。 “最重要的是它会引发异常”......这是“保证”在你的情况下永远不会发生,不是吗? :)

标签: scala functional-programming pattern-matching


【解决方案1】:

第一个为什么不选择 Option.get,如果你 100% 肯定会有结果。 第二个 Option.getOrElse 还将涵盖更新对象在您能够检索它之前消失的极端情况。

这样的事情怎么样:

    T.findOne("id == objectId").map(Right(200,_._2)).getOrElse(Left(404,"Insane Corner Case : Updated Object not found"))

【讨论】:

  • 看看下面我的回答。 map可以写成map((200,_)),然后可以调用toRight,这是一个Option方法。
  • 当然可以,我以前从未见过。现在我已经阅读了它的 scaladoc,我认为我没有错过任何优雅的东西。它是倒着读的:你作为参数提供的东西绝对不是“右”而是“左”——倒过来:),而“getOrElse”似乎很自然。
【解决方案2】:

我决定考虑“极端”情况。

代码已重构为:

T
.findOne("id == objectId")
.map((200, _))
.toRight(404, "Object has been deleted")

感谢 m-z 的提示。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-08
    • 2011-10-14
    • 2015-08-13
    • 1970-01-01
    相关资源
    最近更新 更多