我在 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 用作 Scala 2.11.6 的 IDE
在我看来这是 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
换句话说,您正在返回 Unit
, Unit
类型的伴生对象。该伴生对象的类型为 Unit.type
,它与 Unit
的类型不同(这适用于 Scala 中的所有伴生对象)。
您需要实际返回一个 Unit
类型的值。 As outlined in the docs , 唯一这样的值是 ()
。
所以,你的默认函数应该是:(a: Any) => ()
.
编辑:关于补充问题。
单位换算
这里:
val a: Any => Unit = (a: Any) => Unit
您正在显式键入表达式以具有 Unit
的返回类型。通常它会导致类型错误,但是(正如您所怀疑的)“幸运”您触发了 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"
产生相同的结果。
关于scala - scala中的奇怪类型推断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34131642/