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 Unit
,Unit
类型 的 伴随对象。该伴生对象的类型 Unit.type
与 Unit
不同 类型(这适用于 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"
产生相同的结果。
我在 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 Unit
,Unit
类型 的 伴随对象。该伴生对象的类型 Unit.type
与 Unit
不同 类型(这适用于 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"
产生相同的结果。