在 Scala 中,为什么我可以在此处使用 `Unit` 作为 return 类型?

In Scala, why can I use `Unit` as return type here?

代码如下:

scala> def f(x:Int => Unit):Unit = 1
<console>:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
       def f(x:Int => Unit):Unit = 1
                                   ^
f: (x: Int => Unit)Unit

scala> f(_=>2);
<console>:9: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
              f(_=>2);
                   ^

scala> f(_=>List(1,2));

上面的所有三个表达式在 REPL 中都有效(有一些警告),但它们看起来有点混乱..

在第一个表达式中,f 的 return 类型是 Unit,它是 AnyVal 的子类型而不是 Int 的超类型,因此,我无法理解为什么 1 可以用作 returned 值。

在第二个表达式中,_=>2 还使用 2 而不是 Unit 作为 returned 值,这与定义冲突。

在第三个表达式中,_=> List(1,2) 甚至使用 ListAnyRef 的子类型作为 returned 值,但是 REPL 仍然没有抱怨这个..

有没有人知道为什么 Unit 可以容忍这里的非子类型类型转换?谢谢!

Scala 会在这种情况下自动插入 ()(单例 Unit 值)以进行类型检查。所以你所拥有的相当于:

def f(x:Int => Unit):Unit = { 1; () }

这在 Scala 中称为 "value discarding"。来自 spec:

Value Discarding

If e has some value type and the expected type is Unit, e is converted to the expected type by embedding it in the term { e; () }

就像在许多编程语言中一样,这只是为了方便 "throwing out" 表达式的 return 值。这允许您创建一个 Unit 类型的方法,它只使用表达式的副作用。

检查 SLS 中的 implicit conversions 部分

ValueDiscarding. If e has some value type and the expected type is Unit, e is converted to the expected type by embedding it in the term {e; () }.

另外Ben Reich的回答:

从概念上讲,在 Scala 中,类型 Unit 是所有其他类型的超类型。因此,每个值,包括 Int,都可以分配给 Unit。实际上,如果用作方法的 return 类型,编译器将丢弃结果值,将方法赋予 JVM/Java void 类型。

Nothing 恰恰相反,顺便说一句:从概念上讲,它是所有其他类型的子类型。由于不存在 Nothing 的实例,因此任何其他类型的实例都不能与 Nothing.

赋值兼容

Java 的 void 不知何故是两者的不完整混合。