【问题标题】:In Scala, what is an "early initializer"?在 Scala 中,什么是“早期初始化器”?
【发布时间】:2011-06-10 09:26:35
【问题描述】:

在 Martin Odersky 在 Scala 中的 recent post about levels of programmer ability 中,在 Expert library Designer 部分中,他包含了术语“早期初始化器”

Programming in Scala 中没有提到这些。它们是什么?

【问题讨论】:

  • 它们在 Scala 编程的第 20.5 节中进行了描述,但称为“预初始化字段”。

标签: scala


【解决方案1】:

早期初始化器是子类构造函数的一部分,它打算在其超类之前运行。例如:

abstract class X {
    val name: String
    val size = name.size
}

class Y extends {
    val name = "class Y"
} with X

如果代码被写成

class Z extends X {
    val name = "class Z"
}

那么当Z被初始化时会发生空指针异常,因为在正常的初始化顺序中sizename之前被初始化(超类在类之前)。

【讨论】:

  • 这在什么方面比被 def nameInit = "foo" 覆盖的笨拙命名的 def nameInit: String; val name = nameInit 更可取?
  • @nadavwr A def 将被类的方法表覆盖,从而保证将执行最具体的版本,而 val 初始化没有这样的事情——什么被覆盖是吸气剂,而不是初始化。
【解决方案2】:

据我所知,动机(如上面的链接所示)是:

“当一个 val 被覆盖时,自然不会多次初始化它。因此,尽管上面示例中的 x2 似乎在每个点都定义了,但事实并非如此:被覆盖的 val 在构造过程中会显示为 null超类,抽象 val 也是如此。”

我完全不明白为什么这是自然的。 r.h.s. 完全有可能。分配可能会产生副作用。请注意,这种代码结构在 C++ 或 Java 中是完全不可能的(我猜是 Smalltalk,虽然我不会说那种语言)。实际上,您必须通过构造函数在这些语言中隐式地进行这种双重分配...ticilpmi...EXplicit。根据 r.h.s.副作用的不确定性,这似乎根本不是一个动机:通过分配回避超类副作用(从而使超类不变量无效)的能力?咳!

允许这种不安全的代码结构还有其他“杀手”动机吗?面向对象的语言已经没有这种机制了大约 40 年(如果从语言的创建算起,则有 30 多年),为什么现在包括它?

它...只是...看起来...很危险。

【讨论】:

  • 这对我来说也不完全有意义,我会争辩说,一旦我开始覆盖 vals,我就已经处于危险的境地。覆盖分配给 val 的 def 对我来说更有意义。踢球风格建议:"implicit...ticilpmi...EXplicit" --> "impli^H^H^H^H^HEXplicit"
  • 显然有人从未使用过纸质终端...是的,孩子们...他们曾经使用过 :-)
【解决方案3】:

转念一想,一年一层……

这只是蛋糕。从字面上看。

不是早期的任何东西。只是蛋糕(混合)。

Cake 是 The Grand Pooh-bah 自己创造的一个术语/模式,它采用了 Scala 的 trait 系统,介于类和接口之间。远胜Java的装饰模式。

所谓的“接口”只是一个未命名的基类,而曾经是基类的东西正在充当特征(坦率地说我不知道​​可以这样做)。我不清楚“with'd”类是否可以接受参数(特征不能),是否会尝试并报告。

这个问题及其答案已经成为 Scala 最酷的特性之一。阅读并敬畏。

【讨论】:

  • 来自 Scala 的 EBNF:ClassTemplate ::= [EarlyDefs] ClassParents [TemplateBody]ClassParents ::= Constr {'with' AnnotType}Constr ::= AnnotType {'(' [Exprs] ')'},我想说 "with'd" 类可以接受参数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-19
  • 1970-01-01
  • 2019-11-17
  • 2011-04-28
相关资源
最近更新 更多