Ruby 是ObjectSpace.each_对象返回的枚举数,按对象创建时间排序?

Ruby 是ObjectSpace.each_对象返回的枚举数,按对象创建时间排序?,ruby,Ruby,ObjectSpace。每个对象(ExampleClass)返回ExampleClass所有实例的枚举数。此枚举数是否保证按对象创建时间排序?从最低限度的测试来看,情况似乎是这样的,尽管如前所述,它可能基于实现,我不建议在生产环境中使用,但 class R; end m = 1000.times.map {R.new} os = ObjectSpace.each_object(R).to_a m.reverse.each_with_index.all? {|e,i| e === os[i]} #

ObjectSpace。每个对象(ExampleClass)
返回ExampleClass所有实例的枚举数。此枚举数是否保证按对象创建时间排序?

从最低限度的测试来看,情况似乎是这样的,尽管如前所述,它可能基于实现,我不建议在生产环境中使用,但

class R; end
m = 1000.times.map {R.new}
os = ObjectSpace.each_object(R).to_a
m.reverse.each_with_index.all? {|e,i| e === os[i]}
#=> true

使用
ObjectSpace
的另一个问题是垃圾收集。一旦某个对象超出范围,GC将例行清理这些对象,因此您可能会在较早的对象之前丢失一个较新的对象,具体取决于此,因此我不建议将此过程作为保留所需“id”的准确方法。

我认为更传统的方法是这样做:

class A
  attr_reader :instance_id

  def initialize
    new_id = (self.class.last_instance_id || self.class.first_id-1) + 1
    self.class.instance_variable_set(:@last_instance_id, new_id)
    @instance_id = new_id 
  end

  def self.set_first_id(first_id)
    @first_id = id
  end

  singleton_class.send(:attr_accessor, :first_id)
  singleton_class.send(:attr_reader, :last_instance_id)
end

A.first_id = 0       
a0 = A.new         #=> #<A:0x007fe2bb8c3de0 @instance_id=0> 
a0.instance_id     #=> 0

a1 = A.new         #=> #<A:0x007fe2bb8b87d8 @instance_id=1> 
a1.instance_id     #=> 1 

a2 = A.new         #=> #<A:0x007fe2bb8aa2c8 @instance_id=2> 
a2.instance_id     #=> 2 

A.last_instance_id #=> 2
A类
属性读取器:实例id
def初始化
new_id=(self.class.last_instance_id | self.class.first_id-1)+1
self.class.instance_variable_set(:@last_instance_id,new_id)
@实例\u id=新的\u id
结束
定义自我设置首个id(首个id)
@第一个id=id
结束
singleton_class.send(:attr_访问器,:first_id)
singleton_class.send(:attr_reader,:last_instance_id)
结束
A.first_id=0
a0=A.新的
a0.instance_id#=>0
a1=A.新的
a1.U实例id#=>1
a2=A.新的
a2.实例id#=>2
A.last_instance_id#=>2

您为什么想知道?(只是好奇。)@CarySwoveland我正在创建一个类,该类根据上次创建的实例的id为新实例设置@id。我可以使用类变量来实现这一点,但通常它们被认为是不好的做法(因为它们在继承中被忽略)。我想我可以使用
ObjectSpace来实现这一点。每个对象(ExampleClass)[0]
。文档没有这样的保证,所以我假设这是一个实现细节,可能会发生变化。我可以使用类变量来实现这一点,但通常它们被认为是不好的做法(因为它们在继承中被忽略)--那么为什么不能使用类实例变量呢?@7stud也有继承问题,因为类实例变量根本不是继承的,对吧?回答得很好。您还可以通过将常量放置在类中来包含其范围。e、 g.
A类;第一个_ID=0;。。。;这样结束
如果他想在其他类中使用类似的功能,他不必想出大量不同的术语。@engineersmnky,很好。我决定将第一个id设置为类实例变量而不是常量,从而使该方法更加健壮。“XY答案”是一个很好的触摸,一个必要的术语。这是一个很好的答案。在我的例子中,我想回收和循环ID,所以这有点复杂,但我可以调整它。我没有考虑让实例创建类实例变量,而不是直接在类中设置它。实际上,出于这个原因,我特别选择了ObjectSpace。我想回收程序不再使用的ID。@Ruby有趣的是,你只会“回收”其中的一部分,而且几乎不会按数字顺序进行。例如,如果GC提取了#3,但#62仍然存在,那么根据你的概念,下一个将是#63。这些新对象很少会以增量形式结束,即使它们以增量形式结束,术语id也会产生极大的误导。@rubysimon如果您真的想回收它们,那么将它们的实现包装在管理类或模块中似乎更有意义,将创建的对象存储在数组中。通过这种方式,您将能够找到id中的漏洞,但id也会有点误导。如果有可用的id,它将在999后返回。我真的不在乎这些身份证是否马上被回收。我希望下一个id是最后一个id+1,除非最后一个id是999@engineersmnky