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/Javavoid
type
顺便说一句,Nothing
正好相反:从概念上讲,它是其他类型的子类型。由于不存在Nothing
的实例,因此任何其他类型的实例都不能与Nothing
兼容
Java的
void
在某种程度上是两者的不完全混合。请注意,您可以使用-Ywarn value discard
来警告这一点。您是否将Unit
与Any
混为一谈?@acjay No。这是Unit和Nothing的概念。它不是Scala发明的;许多强类型函数式语言都有相同的概念。名字有时可能会不同,例如,没有什么可以称为底部。我没有投反对票,但现在我投了你更高的票,让你再次当选:)哦,谢谢:-)我不认为你投了反对票,这是不对的<代码>单元不是所有其他类型的超级类型Unit
是AnyVal
的一个子类型,这是一组非常有限的类型。看。并不是将Int
赋值给Unit
,而是编译器通过插入完全丢弃Int
值;()
。在其他语言中可能有所不同,但在Scala中并非如此。