Smalltalk中定义的类变量在哪里?

Smalltalk中定义的类变量在哪里?,smalltalk,Smalltalk,我想知道,如果我定义了一个新的类变量,例如类MyClass,那么定义是在MyClass中还是在MyClass中?MyClass类知道新的类变量吗?是的,类变量与类和元类共享。它们还与所有子类(及其元类)共享。类变量通常大写,以更好地传达在比类更广的范围内共享的想法。在类(而不是元类)中定义类变量 类变量不应与类实例变量混淆,类实例变量是在元类级别定义的实例变量,即类对象的实例变量。尽管这个概念很简单(或者因为它),但它还是有点模糊:实例变量总是在类中定义,以定义其实例的形状(槽)。因此,如果我们

我想知道,如果我定义了一个新的类变量,例如类
MyClass
,那么定义是在
MyClass
中还是在
MyClass
中?
MyClass类
知道新的类变量吗?

是的,类变量与类和元类共享。它们还与所有子类(及其元类)共享。类变量通常大写,以更好地传达在比类更广的范围内共享的想法。在类(而不是元类)中定义类变量

类变量不应与类实例变量混淆,类实例变量是在元类级别定义的实例变量,即类对象的实例变量。尽管这个概念很简单(或者因为它),但它还是有点模糊:实例变量总是在类中定义,以定义其实例的形状(槽)。因此,如果我们将此定义应用于元类(类的类),则此处定义的实例变量定义其实例的形状,其中(通常)只有一个实例,即类

回到类变量,在类(inst端)中定义它们,并在元类(即类端)中初始化它们。请记住,从某种意义上讲,这些是(部分)全局性的,将在实例、子实例、子类和元类之间共享,因此必须像处理全局性的一样小心处理它们


再澄清一次

当我们说实例变量在实例和子实例之间共享时,我们指的是它们的名称(以及对象插槽内存中的位置);我们不是指它们的值(所述插槽的内容)。因此,如果类定义了ivar
color
,则类
C
的两个实例将共享名称,例如
color
,但它们在每个实例上的值将是独立的。换句话说,共享的是名称,而不是值

对于类变量,共享的是名称和值。它实际上是
关联
对象,例如
主题->主题
,即共享的内容。因此,对类变量值的任何修改都会影响其所有引用。类实例变量的情况并非如此,因为它们只是实例变量,只是它们塑造了类及其子类,而不是常规实例和子实例



有关Smalltalk变量的更多信息,请参见

作为Leandro答案的补充,以下是解释实例端(类)和类端(元类)之间共享类变量的主要Squeak实现特定方法:

其中,
thisClass
是元类的唯一实例,即类本身

不过,在大多数Smalltalk方言中很有可能找到类似的实现

编译器将首先尝试将变量解析为方法/块临时变量(包括methd/块参数),然后解析为实例变量,然后解析为共享变量

classPool方法由编译器在最后阶段发送

Leandro解释说,编译器要么将绑定解析为实例变量slot或method临时变量情况下直接在字节码中转录的偏移量,要么解析为共享变量case的一种关联,此关联通常添加到CompiledMethod文本中,并在处理此变量的所有方法之间有效共享(所有方法都指向有效共享的同一关联对象)

编译器部分更特定于方言,在Squeak中,它是用于解析共享变量绑定的方法:

class>>bindingOf: varName environment: anEnvironment
    "Answer the binding of some variable resolved in the scope of the receiver"
    | aSymbol binding |
    aSymbol := varName asSymbol.

    "First look in local classVar dictionary."
    binding := self classPool bindingOf: aSymbol.
    binding ifNotNil:[^binding].

    "Next look in local shared pools."
    self sharedPools do:[:pool | 
        binding := pool bindingOf: aSymbol.
        binding ifNotNil:[^binding].
    ].

    "Next look into superclass pools"
    superclass ifNotNil: [^ superclass bindingOf: aSymbol environment: anEnvironment].

    "No more superclass... Last look in declared environment."
    ^anEnvironment bindingOf: aSymbol

这是为了提醒您,Smalltalk最有趣的部分之一是您可以从IDE中深入了解实现,Smalltalk基本上是用Smalltalk编写的

所以,如果元类不是单例,那就意味着类变量将在元类的所有实例之间共享?@EL_9这并不明显,请看我的答案中的原因。这取决于类池在元类中的定义方式。如果它有多个实例(这意味着多个类共享同一个元类),那么我们最终可以将类池定义为所有实例的类池的并集。我们需要定义如何解决冲突,元类也继承了它的实例超类元类,这将使多个实例的事情变得非常复杂,等等。。。。。。或者,我们必须将类池附加到元类,而不是类,并在元类
^classPool“实例变量”
中,在类
^self class classPool
class>>bindingOf: varName environment: anEnvironment
    "Answer the binding of some variable resolved in the scope of the receiver"
    | aSymbol binding |
    aSymbol := varName asSymbol.

    "First look in local classVar dictionary."
    binding := self classPool bindingOf: aSymbol.
    binding ifNotNil:[^binding].

    "Next look in local shared pools."
    self sharedPools do:[:pool | 
        binding := pool bindingOf: aSymbol.
        binding ifNotNil:[^binding].
    ].

    "Next look into superclass pools"
    superclass ifNotNil: [^ superclass bindingOf: aSymbol environment: anEnvironment].

    "No more superclass... Last look in declared environment."
    ^anEnvironment bindingOf: aSymbol