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
不同。我想增加的灵活性有其成本和收益。
假设我们有一个 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
不同。我想增加的灵活性有其成本和收益。