Scala 中的奇怪类型推断

Weird type inference in scala

我在 Scala 类型推断方面遇到了一些问题。 在下面的工作表示例中,我定义了一个 Map,它将 Any 值映射到一个函数 returning 一个 Unit 值。

有趣的是,当我尝试仅使用一行代码定义同一张地图时它不起作用,因为 'bar' 函数 return 类型突然变为 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

在我看来这是一个 Feature/Bug Scala 编译器,还是我遗漏了什么?

顺便说一句,我刚刚注意到当我像这样在 '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

换句话说,您正在 returning UnitUnit 类型 的 伴随对象。该伴生对象的类型 Unit.typeUnit 不同 类型(这适用于 Scala 中的所有伴生对象)。

您实际上需要 return 类型 Unit 的值。 As outlined in the docs唯一这样的值是 ()

所以,你的默认函数应该是:(a: Any) => ().


编辑:关于补充问题。

单位换算

这里:

val a: Any => Unit = (a: Any) => Unit

您正在明确键入表达式以具有 return 类型的 Unit。通常它会导致类型错误,但是(正如您所怀疑的那样)"fortunately" 您触发了 one of the pre-defined implicit value conversions,特别是:

Value Discarding

If e has some value type and the expected type is Unit, e is converted to the expected type by embedding it in the term { e; () }.

所以,这个:

(a: Any) => Unit  //return type is Unit.type

变成:

(a: Any) => {Unit; ();} //return type is Unit

请注意,根据定义,转换适用于任何值,例如val c: Unit = "c" 产生相同的结果。