在Scala中,什么是;早期初始值设定项“;?

在Scala中,什么是;早期初始值设定项“;?,scala,Scala,在Martin Odersky的《Scala》中,在“专家库设计师”一节中,他加入了术语“早期初始化者” 这些都没有提到。它们是什么?早期初始值设定项是子类构造函数的一部分,该子类要在其超类之前运行。例如: abstract class X { val name: String val size = name.size } class Y extends { val name = "class Y" } with X 如果代码编写为 class Z extends X

在Martin Odersky的《Scala》中,在“专家库设计师”一节中,他加入了术语“早期初始化者”


这些都没有提到。它们是什么?

早期初始值设定项是子类构造函数的一部分,该子类要在其超类之前运行。例如:

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
之前以正常的初始化顺序初始化的(类之前的超类)。

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

当然,当val被重写时,它不会被多次初始化。因此,尽管上面示例中的x2似乎在每个点都定义了,但情况并非如此:在构造超类时,被重写的val和抽象val都将显示为null

我不明白为什么这是很自然的。分配的r.h.s.完全可能有副作用。请注意,无论C++还是java,这种代码结构都是完全不可能的(我猜SimalTalk,虽然我不能为那种语言说话)。事实上,在这些语言中,您必须通过构造函数使这种双重赋值隐式…ticilpmi…显式。考虑到r.h.s.副作用的不确定性,这似乎根本不是一个动机:通过赋值避开超类副作用(从而使超类不变量无效)的能力?哎呀

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


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

再想想,一年一层

这只是蛋糕。真的

一点也不早。只是蛋糕(混合)

Cake是Grand Pooh bah自己创造的一个术语/模式,它使用Scala的特质系统,介于类和接口之间。它比Java的装饰模式要好得多

所谓的“接口”只是一个未命名的基类,而以前的基类只是一个特性(坦白说,我不知道这是可以做到的)。我不清楚“with'd”类是否可以接受参数(traits不能),是否会尝试并报告


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

在Scala编程的第20.5节中有描述,但称为“预初始化字段”。这对我来说也没有完全意义,我认为一旦我开始覆盖VAL,我已经处于危险的境地。重写分配给val的def对我来说更有意义。对kicks的风格建议:“implicit…ticilpmi…EXplicit”->“impliEXplicit”显然有人从来没有使用过纸质终端……是的,孩子们……他们曾经使用过:-)以什么方式比笨拙命名的
def nameInit:String更可取;val name=nameInit
,被
def nameInit=“foo”
覆盖?@nadavwr A
def
将被类的方法表覆盖,从而保证执行最具体的版本,而
val
初始化没有这样的事情——被覆盖的是getter,不是初始化。从Scala的EBNF:
ClassTemplate:=[EarlyDefs]ClassParents[TemplateBody]
ClassParents::=Constr{'with'AnnotType}
Constr::=AnnotType{'('[Exprs]')}
,我认为“with'd”类可以接受参数。