在Scala中,什么是“早期初始化程序”?


Answers:


104

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

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初始化时会发生空指针异常,这size是因为初始化是按照初始化name的常规顺序进行的(类之前的超类)。


用什么方法比笨拙的名称def nameInit: String; val name = nameInit(被覆盖)更可取def nameInit = "foo"
nadavwr

2
@nadavwr Adef将被类的方法表覆盖,从而保证将执行最特定的版本,而val初始化没有这样的东西-被覆盖的是吸气剂,而不是初始化。
Daniel C. Sobral

2

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

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

我不明白为什么这是自然的。分配的rhs完全可能有副作用。请注意,无论在C ++还是Java中,这样的代码结构都是完全不可能的(我会猜测Smalltalk,尽管我不能说那种语言)。实际上,您必须通过构造函数在这些语言中隐式... ticilpmi ... EXPICTIVE这样的双重分配。鉴于rhs副作用的不确定性,这实际上似乎根本不是什么动机:通过ASSIGNMENT避开超类副作用(从而使超类不变式无效)的能力吗?ck!

是否还有其他“杀手级”动机允许这种不安全的代码结构?面向对象的语言在没有这种机制的情况下已经使用了大约40年(如果从创建语言的时间算起,大约30多年),为什么现在要包含它呢?

只是……似乎……很危险。


这对我来说也不是完全有意义,我会争辩说,一旦我开始覆盖val,我就已经处于危险境地。覆盖分配给val的def对我来说更有意义。踢的风格建议:“隐式... ticilpmi ... EXplicit”->“ impli ^ H ^ H ^ H ^ H ^ H EXplicit”
nadavwr

显然有人从未使用过纸质终端机……是的,孩子们……他们曾经有过这种
终端机

1

再三考虑,一年层……

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

不算早。只是蛋糕(mixins)。

Cake是由The Pooh-bah本人创造的一个术语/模式,它采用Scala的特征系统,该系统位于类和界面之间。它远比Java的修饰样式好。

所谓的“接口”仅是一个未命名的基类,而以前作为基类的是作为特征(我坦率地不知道可以做到)。我不清楚“ withd”类是否可以接受参数(特征不能接受),是否可以尝试并进行报告。

这个问题及其答案已进入Scala最酷的功能之一。阅读它,敬畏。


从斯卡拉的EBNF: ClassTemplate ::= [EarlyDefs] ClassParents [TemplateBody]ClassParents ::= Constr {'with' AnnotType}Constr ::= AnnotType {'(' [Exprs] ')'},我会说,“with'd”类可以带参数。
themarketka
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.