Scala中Null / Nothing / Unit的用法

时间:2013-04-23 15:34:08

标签: scala

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

据我了解,Null是一个特征,其唯一的例子是null

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

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


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


除了返回类型之外,您是否将Unit / Null / Nothing用作其他内容?

8 个答案:

答案 0 :(得分:73)

如果方法永远不会返回(意味着它无法通过返回正常完成,它可能会抛出异常),则只使用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。有一个值单位,所以它实际上可以返回。来自API docs

  

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

答案 1 :(得分:16)

您引用的文章可能会产生误导。 Null类型用于与 Java虚拟机兼容,特别是Java。

我们必须考虑 Scala

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

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

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

之外你不能传递任何东西

答案 2 :(得分:15)

  

你是否有单位/零/无的用法除了   返回类型?


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

答案 3 :(得分:5)

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

答案 4 :(得分:5)

如果您使用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]

答案 5 :(得分:3)

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

答案 6 :(得分:1)

以下是来自Nothing的{​​{1}}的示例:

scala.predef

如果您不熟悉(并且搜索引擎无法对其进行搜索), def ??? : Nothing = throw new NotImplementedError 是Scala的占位符函数,用于尚未实施的任何内容。就像Kotlin的???

创建模拟对象时可以使用相同的技巧:使用自定义TODO方法覆盖未使用的方法。不使用notUsed的好处是你不会为你从未打算实现的事情获得编译警告。

答案 7 :(得分:0)

就类别理论而言,没有初始对象,而 Unit 终端对象

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

初始对象也称为共同终端通用,而终端对象也称为最终

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