为什么Unit是其他任何类型的超类型?

时间:2016-11-01 05:57:18

标签: scala

以下是一个例子:

$ scala
Welcome to Scala 2.11.8 (OpenJDK 64-Bit Server VM, Java 1.8.0_112).
Type in expressions for evaluation. Or try :help.

scala> val a: Unit = 1
<console>:11: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
       val a: Unit = 1
                     ^
a: Unit = ()

在Scala文档中:

There is only one value of type Unit, ()

为什么Scala编译器会默默地将值强制转换为Unit?

一些上下文:我使用Future[Unit]类型来描述一些不返回任何内容的过程。由于Future[Unit]现在实际上是Unit的子类型,我得到了一些有趣的错误(someFuture.map(a => Future(a))默默地跳过调用操作而不是给出编译警告)。我应该使用什么作为一种不会返回任何有意义结果的操作?

2 个答案:

答案 0 :(得分:5)

Unit不是其他类型的超类型。相反,所谓的值丢弃称为:当表达式e的预期类型为Unit时,编译器将其替换为{e; ()}。这样做是为了使某些行为更加熟悉。例如。

val sb = new StringBuilder
val strings: List[String] = ...
for (str <- strings) { sb.append(str) }

与其他语言中的for循环类比,我们希望它能够编译。但是,如果没有价值丢弃它就不会:strings.foreach(str => sb.append(str))相当于str => sb.append(str)的类型String => StringBuilder(因为append上的所有StringBuilder方法返回构建器本身)foreach上的List[String]需要String => Unit

您可以添加-Ywarn-value-discard编译器选项,以便在发生时向您发出警告(并明确写入for (sb <- sbOpt) { sb.append("a"); () })。

或者您实际上可以使用a trick定义自己的Unit(可能更改名称以避免混淆任何人阅读您的代码):

 object Unit 
 type Unit = Unit.type 

 implicit def unit2scalaunit(a: Unit): scala.Unit = () 
 implicit def scalaunit2unit(a: scala.Unit): Unit = Unit 

这应避免遇到您所描述的Future问题。

答案 1 :(得分:1)

Unit 不是一切的超类型! Scala实际上有各种各样的转换自动发生,这就是其中之一。从Scala语言规范的section 6.26.1 Value Conversions开始,其中一次转化是

  

价值丢弃

     

如果e具有某种值类型且预期类型为Unit,则会转换e   通过将其嵌入术语{ e; () }中来预期类型。

因此,当您编写类似val a: Unit = 1的内容时,它会被处理为val a: Unit = { 1; () },这是完全不同的。这里的警告实际上非常有用 - 它警告你你可能做错了:你试图放入语句位置的表达式是纯的(没有副作用),所以执行它没有任何效果(除非可能导致关于最终产出的分歧程序。