Java 在Scala中,为什么我可以在这里使用'Unit'作为返回类型?

Java 在Scala中,为什么我可以在这里使用'Unit'作为返回类型?,java,scala,types,functional-programming,type-inference,Java,Scala,Types,Functional Programming,Type Inference,代码如下: 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 ^

代码如下:

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));
scala>def(x:Int=>Unit):Unit=1
:7:警告:纯表达式在语句位置不起任何作用;您可能省略了必要的括号
def f(x:Int=>单位):单位=1
^
f:(x:Int=>Unit)单位
scala>f(=>2);
:9:警告:纯表达式在语句位置不起任何作用;您可能省略了必要的括号
f(=>2);
^
scala>f(=>List(1,2));
上面的三个表达式都在REPL中工作(有一些警告),但它们看起来有点混乱

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

在第二个表达式中,
\u=>2
也使用
2
而不是
Unit
作为返回值,这与定义冲突

在第三个表达式中,
\=>List(1,2)
甚至使用
List
AnyRef
的子类型作为返回值,但REPL仍然没有对此表示不满


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

在这种情况下,Scala将自动插入
()
(单例
单位
值),以便进行类型检查。因此,您所拥有的相当于:

def f(x:Int => Unit):Unit = { 1; () }
这在Scala中称为“值丢弃”。从:

价值丢弃

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

与许多编程语言一样,这只是为了方便“抛出”表达式的返回值。这允许您创建类型为
Unit
的方法,该方法仅使用表达式的副作用。

检查SLS中的部分

值丢弃。 如果e有一些值类型,并且期望的类型是Unit,则通过将e嵌入到术语{e;()}中,将e转换为期望的类型


除了Ben Reich的回答:

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

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


Java的
void
在某种程度上是两者的不完全混合。

请注意,您可以使用
-Ywarn value discard
来警告这一点。您是否将
Unit
Any
混为一谈?@acjay No。这是Unit和Nothing的概念。它不是Scala发明的;许多强类型函数式语言都有相同的概念。名字有时可能会不同,例如,没有什么可以称为底部。我没有投反对票,但现在我投了你更高的票,让你再次当选:)哦,谢谢:-)我不认为你投了反对票,这是不对的<代码>单元不是所有其他类型的超级类型
Unit
AnyVal
的一个子类型,这是一组非常有限的类型。看。并不是将
Int
赋值给
Unit
,而是编译器通过插入
完全丢弃
Int
值;()
。在其他语言中可能有所不同,但在Scala中并非如此。