Smalltalk - 如何获取 Class 的对象(当前实例)中所有实例变量的数组(或集合)?

Smalltallk - How can I get an Array (or Collection) of the all the Instance variables in an Object (the current Instance) of a Class?

假设我们有一个 Class 并对其进行实例化,创建 Class 的实例。此实例有许多(实例)变量,由 class 定义,我需要使用它们。我想将所有这些(实例)变量放在一个数组或某个集合中,这样我就可以遍历它们并将它们设置为某个值,而不是 nil。

我该怎么做?

您可以将 #allInstVarNames 发送到 class(行为)以获取由它和 superclasses 定义的所有实例变量的名称。如果你不需要 superclass 变量,你可以使用 #instVarNames

假设 var 是您需要使用的变量。然后就可以得到实例变量名的集合,并进行迭代

您可以使用 #instVarNamed:put: 按名称设置实例变量,并使用 #instVarNamed: 按名称获取值(以备不时之需)。

我认为这样的事情可能对你有帮助:

var class allInstVarNames do: [ :instVarName |
  var instVarNamed: instVarName put: <yourValue>

我想以@Uko 的回答为基础,因为有更直接的方法来实现他的想法。

发送给Class的消息instSize将回答其实例的命名实例变量的数量。当然,这将包括在 superclasses.

中定义的实例变量

例如,RemoteTempVectorNode instSize 的答案是 17(哇!)。因此你可以这样做:

fields := (1 to: anObject class instSize) collect: [:i | anObject instVarAt: i]

然后,将它们更改为:

values withIndexDo: [:v :i | anObject instVarAt: i put: v]

其中 values 是您要注入对象的新值数组。

那么,为什么我建议这个而不是 instVarNamed:?因为后者是间接的。如果你看一下它的实现,你会发现它必须首先通过将 instVarIndexFor:ifAbsent: 发送到对象的 class 来找出第 i 个 ivar 的名称。换句话说,如果您需要 ivar 名称,请遵循@Uko 的建议;否则不要将它们带入等式,因为它们只会为您的程序添加 CPU 个周期。

还有一件事。正如@Sean DeNegris 在他对你的问题的评论中明智地提出的那样,如果你详细说明为什么你需要这种不寻常的操作,那将是有益的。


编辑:

现在 Pharo 有 Flexible Object Layouts inst var 名称和 class instSize 之间的映射不再有效(在使用新功能的 classes 中。 ) 因此,仅使用索引的更简单方法不具有普遍性。事实上,在新的 "taxonomy" 下,对象的 instSize(字段数)可能与 #numberOfInstanceVariables 不同。我想增加的灵活性有其成本和收益。