我对Scala类型推断有些麻烦.在下面的工作表示例中,我定义了一个Map,它将Any值映射到返回Unit值的函数.
有趣的是,当我尝试使用一行代码定义相同的地图时,它不起作用,因为'bar'函数返回类型突然变为Any而不是Unit.
type UnitFun = (Any) => Unit val foo = "foo" val bar = (a: Any) => System.out.println("bar") val map: Map[Any, UnitFun] = Map().withDefaultValue(((a: Any) => Unit)) val doesCompile: Map[Any, UnitFun] = map + (foo -> bar) val doesNotCompile: Map[Any, UnitFun] = Map().withDefaultValue(((a: Any) => Unit)) + (foo -> bar)
我使用IDEA14作为IDE与Scala 2.11.6
在我看来,这是Scala编译器的功能/ Bug,还是我错过了什么?
顺便说一句我刚注意到当我在'doesNotCompile'中使用'bar'作为默认值时,就像这样:
val doesCompileNow: Map[Any, UnitFun] = Map().withDefaultValue(bar) + (foo -> bar)
它突然似乎有效,我现在非常困惑.:d
编辑1:@Mikolak
在这种情况下,以下代码如何工作?:)
val a: Any => Unit = (a: Any) => Unit val b: Any => Unit = (a: Any) => ()
两个表达式不应该是不同的类型吗?或者是否涉及一些隐式类型转换?
发生编译错误,因为此函数:
(a: Any) => Unit
是类型的
Any => Unit.type
而不是类型:
Any => Unit
换句话说,您将返回该类型Unit
的伴随对象Unit
.该伴随对象具有一种类型Unit.type
,它与不同类型Unit
(这适用于Scala中的所有伴随对象).
你需要的是实际返回一个类型的值Unit
.正如文档中所述,唯一的这样的价值是()
.
所以,你的默认函数应该是:(a: Any) => ()
.
编辑:关于补充问题.
转换为单位这里:
val a: Any => Unit = (a: Any) => Unit
您明确键入表达式以使其返回类型为Unit
.通常它会导致类型错误,但(正如您所怀疑的)"幸运的是" 您触发了一个预定义的隐式值转换,具体来说:
价值丢弃
如果e具有某种值类型且期望的类型是Unit,则通过将e嵌入到术语{e;中来将e转换为期望的类型.()}.
所以这:
(a: Any) => Unit //return type is Unit.type
变为:
(a: Any) => {Unit; ();} //return type is Unit
请注意,根据定义,转换适用于任何值,因此例如val c: Unit = "c"
产生相同的结果.