【问题标题】:Why should you return an Option[Model] when fetching by Id?为什么要在按 Id 获取时返回 Option[Model]?
【发布时间】:2015-12-27 22:03:56
【问题描述】:

我的整个数据库层目前正在为我的所有模型返回一个 Future[Option[Model]]。

我发现这只是让使用 Futures 变得更加困难,更重要的是,我还没有遇到过返回 Option 甚至有意义的用例。
如果 Id 找不到模型,我的应用程序基本上应该崩溃。

我不确定我为什么选择 Option[Model],但什么是最佳实践?

我知道在 RubyonRails 中,当您通过 Id 获取时,即 Model.find(123),如果找不到它会抛出异常。

【问题讨论】:

    标签: scala playframework slick


    【解决方案1】:

    在这种情况下,我当然会选择Future[Model]。即使应用程序不应该“基本上崩溃”,Future 也可能会失败,这很容易处理。使用Future[Option[...]] 在没有结果的情况下成功(例如,您在数据库中有一个可为空的关联)。

    【讨论】:

      【解决方案2】:

      当你可以将选项用作集合时,我发现它非常方便。

      这意味着您可以将输出视为一个集合并对其进行处理,而不是编写嵌套的 if/else 语句来检查 null 然后提取值。

      这导致代码是扁平的,而不是传统的嵌套 if/else 方式。

      您可以在此处阅读有关使用选项的好处

      http://danielwestheide.com/blog/2012/12/19/the-neophytes-guide-to-scala-part-5-the-option-type.html

      【讨论】:

        【解决方案3】:

        我认为你应该坚持Future[Option[Model]] 正是因为不抛出和不捕获异常。如果方法返回类型为Option[Model],则不能错过处理模型不存在的情况。类型签名 hints 有可能是什么都没有返回的情况。调用者必须显式地 mapfold over Option 才能摆脱它并处理内部 Model

        由于所有异常都是未经检查的(并且已检查的异常只是火车残骸),编译器无法提示您处理异常,因此您可能会在运行时感到意外。 Scala 是一种编译型和静态类型的语言,使用类型来描述返回数据是一个非常好的主意,因为编译器会帮助您正确处理所有事情。这在 Ruby 中是不同的!您必须了解静态类型和编译与运行时错误处理的好处。

        同样适用于处理失败的Futures:如果Future 总是成功并且失败Futures 只表示一些意外错误,而不是像“找不到模型”这样的常规内容,你可以只用map over他们没有明确检查他们是否失败。

        在您的情况下,Future[Option[Model] 为您提供更好的错误处理和程序流控制。如果你的 DAO 只是抛出异常,你会得到一个崩溃的应用程序,并带有一些丑陋的堆栈跟踪,以防出错。但是如果你的 DAO 返回Future[Option[Model]],调用者代码可能看起来像这样:

        DAO.findById(id).map { maybeModel: Option[Model] ⇒
          maybeModel match {
            case Some(model) ⇒ processModel(model)
            case None        ⇒ exitWithError(s"Could not find model with id = $id")
          }
        }
        

        (为了便于阅读,代码非常冗长)

        上面的代码让您可以更好地控制应用程序中的退出点,如果您的需求发生变化,这可能非常有用,并且如果找不到模型,您一定不能使应用程序崩溃。例如,您可能会发现所有对 exitWithError 的调用并将它们替换为 logErrorshowErrorMessage 类型的逻辑。如果你有例外,这几乎是不可能的。

        另一个例子:假设你有 2 个 DAO 方法:findById(id: Long): Future[Option[Model]]countById(id: Long): Future[Int]。他们的类型签名表明findById 可能有nothing 可以返回给调用者,这由Option 指示。 countById 总是必须返回 something,这是由普通的 Int 建议的。在针对此 API 进行编码时,调用者了解这两种方法的语义。在调用findById 时,他们应该考虑两种明确的情况:何时找到模型,何时未找到模型。调用countById 时,只需使用返回的任何值,始终为Int

        希望这能让它更清楚:) 随时提出更多问题。

        【讨论】:

        • 问题还在于,处理 Future[Option[Mode]] 非常麻烦,我必须使用映射然后匹配来编写这么多代码。我在我的应用程序中做了很多这样的事情,编写简单的代码变得非常困难。我有很多理解,每个 for-compr 的开头我都会调用 findById。
        • 如果您分享一些代码,我可能会为您提供帮助。你的描述很模糊。如果你使用for 理解,你可能不需要map。您可以在Options 上使用fold 来避免match
        猜你喜欢
        • 2020-11-03
        • 2010-12-23
        • 1970-01-01
        • 2021-07-05
        • 1970-01-01
        • 1970-01-01
        • 2018-07-11
        • 1970-01-01
        • 2015-09-04
        相关资源
        最近更新 更多