我对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编译器的功能/错误,还是我错过了什么?
btw我刚才注意到当我在'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) => ()
两个表达式不应该是不同的类型吗?或者是否涉及一些隐式类型转换?
答案 0 :(得分:9)
发生编译错误是因为此函数:
(a: Any) => Unit
的类型为
Any => Unit.type
和不类型:
Any => Unit
换句话说,您将返回Unit
,Unit
类型的伴随对象。该伴随对象的类型为Unit.type
,与<{1}}类型的不同类型(这适用于Scala中的所有协同对象)。
您需要的是实际返回Unit
类型的值。 As outlined in the docs,唯一的此类值为Unit
。
因此,您的默认功能应为:()
。
编辑:关于补充问题。
下面:
(a: Any) => ()
您明确键入表达式以使返回类型为val a: Any => Unit = (a: Any) => Unit
。通常它会导致类型错误,但(正如您怀疑的那样)“幸运的是”您触发了one of the pre-defined implicit value conversions ,具体来说:
价值放弃
如果e具有某种值类型且预期类型为Unit,则通过将e嵌入到术语{e;中来将e转换为期望类型。 ()}。
所以,这个:
Unit
变为:
(a: Any) => Unit //return type is Unit.type
请注意,根据定义,转化适用于任何值,例如, (a: Any) => {Unit; ();} //return type is Unit
会产生相同的结果。