4

Scala 在 Java 的类型系统上叠加了一个非常优雅的类层次结构,从顶部的 Any 膨胀到 AnyRef 和 A​​nyVal 以分别覆盖 Java 的 Objects 和原语,然后最终收敛,将引用类型折叠为 Null 并将所有类型折叠为 Nothing。据我了解,Nothing 是一切事物的子类型;将 AnyRef/java.lang.Object 的所有子类型的子类型设为空。[见http://www.scala-lang.org/node/128 ]

然而,似乎有一些不规则之处,一些地方不能简单地将所有 Scala 类型视为无缝类型层次结构的元素。我觉得这很烦人,并想了解我可能会感到惊讶的地方。

到目前为止,我知道一些违规行为:

1) 虽然 Null 是 AnyRef 的子类型,但调用 null.isInstanceOf[AnyRef](或 AnyRef 的其他子类型)返回 false。我怀疑选择这与 Java 的 instanceof 运算符的行为一致。

2) 无论方差注释如何,一切都与 Nothing 是协变的。如果我有一个返回未标记为协变的类型 T 的方法,我可以重写该方法以返回 Nothing 类型。[注意:此说法是错误的,请参阅下面的答案和评论!]

3)我不能将 isInstanceOf 应用于类型 AnyVal [请参阅为什么 AnyVal 不能在 isInstanceOf 检查中使用?以及如何测试作为 AnyVal 的值?]

4) 询问某事是否 isInstanceOf[Null] 是非法的,这是一个完全连贯的问题(尽管不是特别必要,因为“myVar == null”会给出相同的答案)

Scala 的类型层次结构中是否还有其他不规则或特殊情况的示例?我觉得这些值得学习和理解,以避免不受欢迎的惊喜。

4

1 回答 1

7

1)"A string is a subtype of AnyRef".isInstanceOf[AnyRef]返回true。对于 的其他子类型也是如此AnyRef,除了Null. 正如您所说,唯一的不规则之处在于与 Java 保持一致。

2) 如果B是 的子类型A,即B <: A,那么您总是可以覆盖一个方法:

def foo: A = ...

到:

override def foo: B = ...

这称为优化返回类型,并且始终是允许的。由于Nothing它是所有其他类型的子类型(Nothing <: Afor all A),因此您始终可以将返回类型细化为Nothing(例如,通过在方法体中抛出异常)。这是一个非常常规的属性。返回类型协方差与类型参数上的方差注释没有直接关系。

3)其他问题很好地涵盖了这一点。

4) 这是因为该Null类型在 Java 运行时中不存在。我想如果你想模仿这个,你可以创建自己的instanceOf方法 - 你首先必须检查参数是否为null,否则,进行正常isInstanceOf检查。

还有其他违规行为,是的。例如:如果 Int 不能为 null,那么 null.asInstanceOf[Int] 是什么意思?

数组是另一个例子,你可以instanceof在运行时通过装箱/拆箱或检查来支付通用数组的一致性。被new Array[Any]转换为对象数组 - 将整数存储到数组中将导致装箱。每当您使用没有上限的 时,每次索引元素时,数组都会与正确的运行时数组类型匹配Array[T]T

为了更好地理解您可能会感到惊讶,考虑这些构造如何转换到 JVM 是很有用的,在 JVM 中存在原始和引用类型、装箱/拆箱和不同数组类的概念。

于 2012-10-10T23:19:15.180 回答