【问题标题】:Usages of Null / Nothing / Unit in ScalaScala 中 Null / Nothing / Unit 的用法
【发布时间】:2018-12-06 00:48:50
【问题描述】:

我刚刚读到:http://oldfashionedsoftware.com/2008/08/20/a-post-about-nothing/

据我了解,Null 是一个特征,它的唯一实例是null

当一个方法接受一个 Null 参数时,我们只能直接传递一个 Null 引用或 null,而不能传递任何其他引用,即使它是 null (例如 nullString: String = null)。

我只是想知道在哪些情况下使用 Null 特征可能有用。 还有一个 Nothing 特质,我真的没有看到更多的例子。


我也不太明白使用 Nothing 和 Unit 作为返回类型有什么区别,因为两者都不返回任何结果,例如当我有一个执行日志记录的方法时如何知道使用哪一个?


除了返回类型之外,您还有 Unit / Null / Nothing 的用法吗?

【问题讨论】:

    标签: scala


    【解决方案1】:

    只有在方法从不返回时才使用 Nothing(这意味着它无法通过返回正常完成,它可能会引发异常)。没有任何东西永远不会被实例化,并且是为了类型系统的利益而存在的(引用 James Iry:"The reason Scala has a bottom type is tied to its ability to express variance in type parameters.")。从您链接到的文章中:

    Nothing 的另一个用途是作为永远不会发生的方法的返回类型 返回。如果您考虑一下,这是有道理的。如果一个方法的返回 type 是 Nothing,绝对不存在 Nothing 的实例, 那么这样的方法决不能返回。

    您的日志记录方法将返回 Unit。有一个值 Unit 所以它实际上可以被返回。来自API docs

    Unit 是 scala.AnyVal 的子类型。类型只有一个值 单位,(),它不被底层的任何对象表示 运行时系统。具有返回类型 Unit 的方法类似于 Java 声明为 void 的方法。

    【讨论】:

    • 谢谢,“永不返回”是指调用无限期阻塞(例如作业调度程序的启动方法?)
    • @Sabastien:它不会正常返回,它可能会抛出异常(参见james-iry.blogspot.com/2009/08/…)。如果阻塞调用仅以抛出异常结束,那么这将计算在内。谢谢你的问题,这需要澄清。
    【解决方案2】:

    您引用的文章可能具有误导性。 Null 类型是为了兼容 Java 虚拟机,尤其是 Java。

    我们必须考虑 Scala

    • 完全面向对象:每个值都是一个对象
    • 是强类型的:每个值都必须有一个类型
    • 需要处理 null 引用以访问,例如,Java 库和代码

    因此,有必要为null 值定义一个类型,即Null 特征,并以null 作为其唯一实例。

    Null 类型没有什么特别有用的,除非你是类型系统或者你在编译器上开发。特别是,我看不出有任何合理的理由为方法定义 Null 类型参数,因为除了 null

    之外,你不能传递任何东西

    【讨论】:

    • 确实如此,所以最后Null没有其他用法了吗?
    • @SebastienLorber 编辑了答案。我实际上看不到普通开发人员的任何用法。也许其他人能想到一些有用的东西。
    • 谢谢。如果我们知道这种事情的原因,我们就会理解它们,否则我们就会记住它们。
    • Null 在您有类型参数并且可能想要返回 null like in this question and answer 时很有用,因为您不鼓励在 scala 中使用 null,但它很少出现,类型系统中可能还有其他用法还有
    【解决方案3】:

    你有 Unit / Null / Nothing 的用法吗? 返回类型?


    Unit可以这样使用:

    def execute(code: => Unit):Unit = {
      // do something before
      code
      // do something after
    }
    

    这允许您传入要执行的任意代码块。


    Null 可以用作任何可以为空的值的底部类型。一个例子是这样的:

    implicit def zeroNull[B >: Null] =
        new Zero[B] { def apply = null }
    

    Nothing用于None的定义

    object None extends Option[Nothing]
    

    这允许您将None 分配给任何类型的Option,因为Nothing“扩展”了所有内容。

    val x:Option[String] = None
    

    【讨论】:

    • 好的。对于您对 Unit 的使用,您可以使用泛型类型,以便如果您的代码块返回除 unit 之外的其他内容,则执行可能会返回此泛型类型。
    • 正如@drexin 在对另一个答案的评论中所说,它主要用于表示副作用。
    【解决方案4】:

    如果您使用Nothing,则无需执行任何操作(包括打印控制台) 如果你做某事,使用输出类型Unit

    object Run extends App {
      //def sayHello(): Nothing = println("hello?")
      def sayHello(): Unit = println("hello?")
      sayHello()
    }
    

    ...那Nothing怎么用?

    trait Option[E]
    case class Some[E](value: E) extends Option[E]
    case object None extends Option[Nothing]
    

    【讨论】:

    • 另外,Option 中的 E 必须处于协变位置:trait Option[+E] 以允许像 val x: Option[Int] = None 这样的事情
    【解决方案5】:

    我从未真正使用过Null 类型,但您使用Unit,而在java 上您将使用voidNothing 是一种特殊类型,因为正如 Nathan 已经提到的,不可能有 Nothing 的实例。 Nothing 是所谓的底部类型,这意味着它是任何其他类型的子类型。这(和逆变类型参数)就是为什么您可以将任何值添加到 Nil - 这是一个 List[Nothing] - 然后列表将属于此元素类型。 None 也属于 Option[Nothing] 类型。每次尝试访问此类容器中的值都会引发异常,因为这是从 Nothing 类型的方法返回的唯一有效方式。

    【讨论】:

    • 谢谢,我不知道 None 扩展了 Option[Nothing]。在子类型可以使用 Nothing 的某些泛型用法中是有意义的(我想很难找到 Null 和 Unit 的示例......)
    • 使用单元,其中会出现副作用,例如 IO monad 可以是 IO[Unit] 类型,用于打印到控制台等。
    • 是的,从来没有使用过 IO monad,将它与 Unit 一起使用是有意义的(如果它是一些产生无限流的 IO 操作,也许没什么?)
    • 不,那里没有任何意义。
    【解决方案6】:

    Nothing 经常被隐式使用。在下面的代码中, val b: Boolean = if (1 > 2) false else throw new RuntimeException("error") else 子句的类型为 Nothing,它是 Boolean(以及任何其他 AnyVal)的子类。因此,整个赋值对编译器都是有效的,尽管 else 子句并没有真正返回任何内容。

    【讨论】:

      【解决方案7】:

      这是来自scala.predefNothing 示例:

        def ??? : Nothing = throw new NotImplementedError
      

      如果您不熟悉(搜索引擎无法搜索)??? 是 Scala 的占位符函数,用于尚未实现的任何内容。就像 Kotlin 的 TODO

      您可以在创建模拟对象时使用相同的技巧:使用自定义 notUsed 方法覆盖未使用的方法。不使用??? 的好处是你不会收到你从未打算实现的东西的编译警告。

      【讨论】:

        【解决方案8】:

        就范畴论而言,Nothing初始对象Unit终端对象。 p>

        https://en.wikipedia.org/wiki/Initial_and_terminal_objects

        初始对象也称为coterminaluniversal终端对象也称为final

        如果一个对象既是 initial 又是 terminal,则称为 zero objectnull 对象。

        【讨论】:

          猜你喜欢
          • 2019-09-21
          • 1970-01-01
          • 2015-11-24
          • 2020-12-17
          • 2015-10-14
          • 2011-10-16
          • 2011-05-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多