【问题标题】:Scala's class hierarchyScala 的类层次结构
【发布时间】:2017-01-24 02:26:02
【问题描述】:

关于 Scala 的类层次结构的问题:

  1. 在 IntelliJ IDE 中,我正在寻找 AnyAnyRef 的实现,但它们不存在。 它们在哪里定义,如何查看它们的代码?

  2. 我在“Scala 编程”中阅读了以下内容

== 不直接调用 equals 的唯一情况是 Java 的 盒装数字类,例如 Integer 或 Long。在 Java 中,一个新的 Integer(1) 不等于新的 Long(1),即使对于原语 值 1 == 1L。由于 Scala 是一种比 Java 更常规的语言,它 有必要通过特殊情况来纠正这种差异 == 这些类的方法。

嗯...但是== 不是最终的吗?他们是如何为 Java 的数字类创建一个特例的?

【问题讨论】:

标签: scala intellij-idea


【解决方案1】:

AnyAnyRefNullNothing 实际上并不存在;包含它们是为了使类型系统完整,但它们没有真正的表示。你可以找到a reference in Scala's repository,但正如它所说,这些实际上并没有编译和存在,仅用于文档和引导目的。 Scala的3个Any*在编译后的字节码中其实都是java.lang.Object

此外,原始值类(IntLong 等)都定义为final abstract,这意味着它们实际上也不存在。他们所有的方法都是抽象的。

为了让一切看起来整洁,更重要的是,为了工作,编译器的工作是假装这些类型的存在并执行魔法让它们粘在一起。这就是允许== 进行空检查并正确处理值类型的原因,即使它是final,因为编译器正在围绕它做魔术。对于new java.lang.Integer(5) == new java.lang.Long(5),归结为scala.runtime.BoxesRuntime.equalsNumNum(new java.lang.Integer(5), new java.lang.Long(5))

【讨论】:

  • 这很神奇,有什么理由不让它更简单吗?另外,你是说编译器实际上违反了最终规则,这不是问题(对于查看参考代码的人来说,虽然它没有编译)?
  • @rapt 在我看来,这 相当简单。在 Scala 领域,我们有一个健全的 normal 类型系统,底部类型为 Nothing,顶部类型为 Any,原语(几乎)是 AnyVal 的普通子类,原语操作如 @ 987654338@ 和 / 作为原始类上的普通抽象方法,等等。当这个系统需要被压缩到 JVM 及其局限性时,魔法就会发生。
  • 我问的不是理想系统的设计,而是实现。实现真正的 Any、AnyRef 以及具体的 Int、具体的 Long 等有什么问题吗?
  • @rapt == 需要标记为final,否则我可以这样做:trait Oops extends Any { override def ==(sucker: Any) = ??? }
  • 是的,我并不是建议不要将== 设为final,而只是说编译器违反了此规则。它不会产生编译错误;问题可能出在代码的读者身上,他们可能会认为它确实是最终的。
【解决方案2】:

语言有这样的“神奇”部分是很正常的。语言本身无法描述的部分。

明显的例子:你可以声明一个超类,或者你不能声明一个超类,在这种情况下超类是AnyRef。那么,没有超类的类Any怎么写呢?好吧,你不能。您可以扩展语言并允许程序员编写没有超类的类,但是您不能再保证 Anyonly 这样的类,因此您的继承层次结构将不再形成格子.但是,类型检查和类型推断规则取决于继承层次结构是一个格子。

因此,唯一明智的选择是定义Any,而该定义实际上无法用语言本身表达。

这不是 Scala 特有的:例如,Java 和 Ruby 的 Object 也有同样的问题。

实际上,与其他主流语言相比,Scala 有很多更少这样的“魔力”……而且它确实拥有的很大一部分“魔力”是为了平台兼容性与底层主机生态系统(Java 用于 Scala-JVM,ECMAScript 用于 Scala.js,CLI 用于废弃的 Scala.NET,CoreFoundation 用于假设的 Scala-macOS 等)。

【讨论】:

  • 对不起,我不明白你的措辞。超类至少有两种含义:父类和最终父类(如 Java 中的 Object)——你指的是哪一种?另外,将Any 设为java.lang.Object 的子类有什么问题,如果我猜对了,您担心Any 仍然有父类——那么为什么不通过编译器禁用它。无论如何,仍然可以从 Scala 访问 Object,所以 Any 并不是真正的终极超类。
  • @rapt Any 实际上是终极超类。类型系统的设计使得Any 高于Object。您可以通过在 REPL 中运行 implicitly[Object <:< Any]implicitly[Object =:= Any] 来证明这一点。第二个错误是因为编译器无法证明Object 等于Any,而第一个错误是因为编译器可以 证明ObjectAny 的子类型。如果您使用implicitly[Object =:= AnyRef],您还会发现它们完全相等。
  • 你说得对,我忽略了这个事实。所以 Any & AnyRef 无论如何都不能真正根据他们的参考代码进行编译。知道非具体值类(Int、Long 等)的原因是什么吗?
  • 1) 这些类型的存在是为了抽象基元和盒装基元之间的区别(Int 将是 int 如果可以,Integer 如果必须)。转换被魔法隐藏了。 2)当你实际上不能使用原语时,你将如何在一个类中实现原语操作(即我如何定义Int.+?)?当编译器看到您执行原始操作时,它会将其转换为实际的字节码而不是方法调用。
  • @rapt:Scala 中没有原语,但在至少一个实现 Scala 的平台(JVM)中存在原语,并且您希望使用原语来实现 Scala 以获得表现。然而,在 Scala 中,一切都是对象,但在 JVM 上,原语不是对象。在 Scala-JVM 实现中这样做的方式是将它们实现为原语,但在编译器中伪造它们的对象性……再说一次,这不是你可以在 Scala 中表达的东西,因为根本不可能表达某种东西的想法不是一种语言中的对象……
猜你喜欢
  • 2011-05-06
  • 2017-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-05
  • 1970-01-01
  • 2012-08-25
相关资源
最近更新 更多