97

我刚刚读过: 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 的用法?

4

8 回答 8

80

只有在方法永远不会返回时才使用 Nothing(这意味着它无法通过返回正常完成,它可能会引发异常)。没有什么是永远不会被实例化的,并且是为了类型系统的利益而存在的(引用 James Iry 的话:“Scala 拥有底层类型的原因与它表达类型参数变化的能力有关。”)。从您链接到的文章中:

Nothing 的另一种用途是作为从不返回的方法的返回类型。如果您考虑一下,这是有道理的。如果一个方法的返回类型是 Nothing,并且绝对不存在 Nothing 的实例,那么这样的方法绝对不能返回。

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

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

于 2013-04-23T15:40:30.263 回答
18

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

我们必须考虑Scala

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

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

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

于 2013-04-23T16:40:46.420 回答
15

除了返回类型之外,您是否有 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]

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

val x:Option[String] = None
于 2013-04-23T16:40:46.820 回答
6

如果您使用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]
于 2016-04-07T04:35:29.627 回答
5

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

于 2013-04-23T15:50:38.023 回答
3

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

于 2017-06-29T23:34:43.790 回答
2

Nothing以下是from的示例scala.predef

  def ??? : Nothing = throw new NotImplementedError

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

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

于 2018-06-06T22:09:19.430 回答
1

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

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

初始对象也称为共同终端或通用终端对象也称为最终对象。

如果一个对象既是初始对象又是终结对象,则称为零对象对象。

于 2018-12-05T16:48:50.747 回答