scala中奇怪的类型推断

时间:2015-12-07 10:42:27

标签: scala dictionary type-inference

我对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) => ()

两个表达式不应该是不同的类型吗?或者是否涉及一些隐式类型转换?

1 个答案:

答案 0 :(得分:9)

原始编译错误

发生编译错误是因为此函数:

(a: Any) => Unit

的类型为

Any => Unit.type

类型:

Any => Unit

换句话说,您将返回UnitUnit类型的伴随对象。该伴随对象的类型为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 会产生相同的结果。