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

Rog*_*ach 2 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 = ()
Run Code Online (Sandbox Code Playgroud)

在Scala文档中:

There is only one value of type Unit, ()
Run Code Online (Sandbox Code Playgroud)

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

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

Ale*_*nov 5

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

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

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

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

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

 object Unit 
 type Unit = Unit.type 

 implicit def unit2scalaunit(a: Unit): scala.Unit = () 
 implicit def scalaunit2unit(a: scala.Unit): Unit = Unit 
Run Code Online (Sandbox Code Playgroud)

这应该避免与Future您描述的问题.

  • 定义我自己的单位会让任何被迫维护我的代码的人感到困惑:)但编译器警告工作得很好,谢谢! (2认同)