【问题标题】:When should I use Option.empty[A] and when should I use None in Scala?什么时候应该使用 Option.empty[A] 什么时候应该在 Scala 中使用 None?
【发布时间】:2016-03-28 06:28:30
【问题描述】:

在 Scala 中,当我想将某些内容设置为 None 时,我有两个选择:使用 NoneOption.empty[A]

我应该只选择一个并始终如一地使用它,还是有时我应该使用一个而不是另一个?

例子:

scala> def f(str: Option[String]) = str
f: (str: Option[String])Option[String]

scala> f(None)
res0: Option[String] = None

scala> f(Option.empty)
res1: Option[String] = None

【问题讨论】:

    标签: scala scala-option


    【解决方案1】:

    我会尽可能坚持None,这几乎总是如此。它更短且被广泛使用。 Option.empty 允许你指定底层值的类型,所以当你需要帮助类型推断时使用它。如果编译器已经知道该类型,None 将按预期工作,但是在定义新变量时

    var a = None
    

    会导致将 a 推断为 None.type,这不太可能是您想要的。

    然后您可以使用以下几种方法中的一种来帮助推断您需要什么

    @ var a = Option.empty[String]
    a: Option[String] = None
    @ var a: Option[String] = None
    a: Option[String] = None
    @ var a = None: Option[String] // this one is rather uncommon
    a: Option[String] = None
    

    编译器需要帮助的另一个地方:

    List(1, 2, 3).foldLeft(Option.empty[String])((a, e) => a.map(s => s + e.toString))
    

    (代码没有意义,仅作为示例)如果您要省略类型,或将其替换为None,则累加器的类型将分别推断为Option[Nothing]None.type

    就我个人而言,这是我会选择Option.empty 的地方,对于其他情况,我会尽可能坚持使用None

    【讨论】:

      【解决方案2】:

      简短的回答使用None 如果谈论一个值,例如在将参数传递给任何函数时,在定义某些东西时使用Option.empty[T]

      var something = Option.empty[String] 表示something 现在是None,但将来可以变成Some("hede")。另一方面,var something = None 没有任何意义。你不能用Some("hede")重新分配它,编译器会生气: found : Some[String] required: None.type 因此,这意味着 NoneOption.empty[T] 不是替代品。您可以将 None 传递给任何 Option[T] 但不能将 Some[T] 传递给 None.type

      【讨论】:

      • 但是如果你分配给 None 并声明类型它是相等的。 x:选项[字符串] = 无。 Empty 让你设置一个类型。
      【解决方案3】:

      鉴于Option[A].empty 只返回None

      /** An Option factory which returns `None` in a manner consistent with
       *  the collections hierarchy.
       */
      def empty[A] : Option[A] = None
      

      我会说:

      1. 如您所说,在整个代码库中保持一致。使其保持一致意味着进入您的代码库的程序员不必担心一件事。 “我应该使用None 还是Option.empty?好吧,我看到@cdmckay 在整个调用库中都使用X,我也会使用它”
      2. 可读性 - 想想什么最能传达你想要的观点。如果你要阅读一个特定的方法,如果它返回一个空的Option(让我们暂时忽略底层实现只是返回None)或显式的None,对你来说更有意义吗? IMO,我认为None 是一个不存在的值,正如文档所指定的那样:

        /** This case object represents non-existent values.
         *
         *  @author  Martin Odersky
         *  @version 1.0, 16/07/2003
         */
        

      【讨论】:

      • 投反对票,因为它没有回答问题(有时是否出于一致性以外的原因首选)。此外,关于空选项比明确的 None 或多或少有意义的观点对我来说似乎很神秘。
      【解决方案4】:

      以下是使用 Scala 和 Scalaz 导出的工作表。

      def f(str: Option[String]) = str              //> f: (str: Option[String])Option[String]
      f(None)                                       //> res1: Option[String] = None
      var x:Option[String]=None                     //> x  : Option[String] = None
      x=Some("test")
      x                                             //> res2: Option[String] = Some(test)
      x=None
      x      
      

      现在使用 Scalaz,

      def fz(str: Option[String]) = str             //> fz: (str: Option[String])Option[String]
      fz(none)                                      //> res4: Option[String] = None
      var xz:Option[String]=none                    //> xz  : Option[String] = None
      xz=some("test")
      xz                                            //> res5: Option[String] = Some(test)
      xz=none
      xz         
      

      请注意,无论您使用None 还是Option.Empty,所有语句的评估方式都相同。如何 ?

      如您所见,通过 var x:Option[String]=None 语句中的返回类型让 Scala 了解您的意图很重要。这允许稍后分配Some。然而,一个简单的 var x=None 将在后面的行中失败,因为这将使变量 x 解析为 None.type 而不是 Option[T]

      我认为应该遵守约定。对于作业,我会选择var x:Option[String]=None 选项。同样,每当使用 None 时,最好使用返回类型(在本例中为 Option[String]),这样分配就不会解析为 None.type
      只有在我无法提供类型并且需要完成一些任务的情况下,我才会选择Option.empty

      【讨论】:

      • 我想不出“它们都解析为 Option[Nothing]”的任何意义。正如其他答案所示,它们不能总是可以互换使用。
      • 是的,你是对的,我说的是 Scalaz,但意思并不清楚。谢谢。我已经更新了答案。
      • 即使在那里,您实际上也会得到none[A]: Option[A]。这是与Option.empty 相同的类型,而不是Option[Nothing];这就是为什么它可以互换使用。如果在 Scala 无法推断的位置使用不带类型参数的 Option[Nothing],则只会得到 Option[Nothing],与 Option.empty 相同。
      • 现在我很困惑。我在工作表 Scalaz 的 noneOption.empty 中看到都解析为 Option[Nothing] 。你有什么建议吗?
      • "如果它在 Scala 无法推断的位置使用时没有类型参数"。您通常不会写val x = none,而是写val x = none[String](或者在编译器需要特定类型的地方使用none,例如问题中的f(none))。
      【解决方案5】:

      正如其他人所指出的,这更多是个人喜好问题,其中大多数人更喜欢None,或者在某些情况下,您明确需要输入类型,因为编译器无法推断。

      这个问题可以外推到其他Scala类,比如SequencesMapSetList等等。在所有这些中,您都有几种定义空状态的方法。使用顺序:

      • Seq()
      • Seq.empty
      • Seq.empty[Type]

      从3开始,我更喜欢第二个,因为:

      • 第一个 (Seq()) 容易出错。好像有人想创建一个序列却忘记添加元素
      • 第二个 (Seq.empty) 明确表示希望拥有一个空序列
      • 虽然第三个 (Seq.empty[Type]) 与第二个一样明确,但它更冗长,所以我通常不使用

      【讨论】:

        猜你喜欢
        • 2023-04-02
        • 2011-04-15
        • 2017-04-10
        • 2012-03-19
        • 2018-05-12
        • 2018-12-11
        • 1970-01-01
        • 2022-09-28
        • 2021-09-07
        相关资源
        最近更新 更多