【问题标题】:How do I list all objects created from a class in Ruby? [duplicate]如何列出从 Ruby 中的类创建的所有对象? [复制]
【发布时间】:2012-12-28 09:23:31
【问题描述】:

Ruby 中有没有办法让一个类知道它存在多少个实例并列出它们?

这是一个示例类:

class Project

  attr_accessor :name, :tasks

  def initialize(options)
    @name = options[:name]
    @tasks = options[:tasks]
  end

  def self.all
    # return listing of project objects
  end

    def self.count
          # return a count of existing projects
    end


end

现在我创建这个类的项目对象:

options1 = {
  name: 'Building house',
  priority: 2,
  tasks: []
}

options2 = {
  name: 'Getting a loan from the Bank',
  priority: 3,
  tasks: []
}

@project1 = Project.new(options1)
@project2 = Project.new(options2)

我想要的是有像Project.allProject.count 这样的类方法来返回当前项目的列表和计数。

我该怎么做?

【问题讨论】:

    标签: ruby oop class-method


    【解决方案1】:

    您可以使用ObjectSpace 模块来执行此操作,特别是each_object 方法。

    ObjectSpace.each_object(Project).count
    

    为了完整起见,以下是您在课堂上使用它的方式(向sawa 致敬)

    class Project
      # ...
    
      def self.all
        ObjectSpace.each_object(self).to_a
      end
    
      def self.count
        all.count
      end
    end
    

    【讨论】:

    • 你需要在课堂上include ObjectSpace 才能使用吗?
    • @HunterStevens 不,我们没有将模块混合到我们的类中,只是在其上调用一个方法
    • 警告:这个解决方案可以很容易地射中自己的脚。如果您不保留对对象的引用(例如,如果您在没有将结果分配给某物的情况下执行 Project.new),它们将在某个时候被垃圾收集,ObjectSpace.each_object 显然会停止报告它们。使用 @@instances = [] 而不是像 rohit89 的答案那样通过保留对这些对象的引用来解决这个问题。
    【解决方案2】:

    一种方法是在创建新实例时跟踪它。

    class Project
    
        @@count = 0
        @@instances = []
    
        def initialize(options)
               @@count += 1
               @@instances << self
        end
    
        def self.all
            @@instances.inspect
        end
    
        def self.count
            @@count
        end
    
    end
    

    如果你想使用ObjectSpace,那么它

    def self.count
        ObjectSpace.each_object(self).count
    end
    
    def self.all
        ObjectSpace.each_object(self).to_a
    end
    

    【讨论】:

    • 这就是我要做的。它肯定适用于所有 Ruby 实现,并且可以根据需要扩展用于不同目的。
    【解决方案3】:
    class Project
        def self.all; ObjectSpace.each_object(self).to_a end
        def self.count; all.length end
    end
    

    【讨论】:

      【解决方案4】:

      也许这会起作用:

      class Project
        class << self; attr_accessor :instances; end
      
        attr_accessor :name, :tasks
      
        def initialize(options)
          @name = options[:name]
          @tasks = options[:tasks]
      
          self.class.instances ||= Array.new
          self.class.instances << self
        end
      
        def self.all
          # return listing of project objects
          instances ? instances.dup : []
        end
      
        def self.count
          # return a count of existing projects
          instances ? instances.count : 0 
        end
      
        def destroy
          self.class.instances.delete(self)
        end
      end
      

      但您必须手动销毁这些对象。也许可以基于 ObjectSpace 模块构建其他解决方案。

      【讨论】:

      • 我喜欢这个,但是应该有一些内置的反射 - ruby​​ 中不存在吗?我不知道如何使用 ObjectSpace 模块。例子真的很有帮助
      • 好吧。 ObjectSpace 允许您与垃圾收集器交互。这是我在代码中尽量不做的事情。你可以试试ObjectSpace.each_object(Project).to_a,但我不能再帮你了。
      • 有什么特别的理由可以避免这种情况吗?
      • 例如在doc 中写到方法count_objects 是“除了C Ruby 之外预计不会工作”。所以你必须小心。
      • count_objects 仅适用于 MRI(又名 C Ruby)。 each_object 适用于 MRI、Rubinius 和 JRuby(在 1.9.3 变体上测试)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-27
      • 2021-11-22
      • 2020-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-06
      相关资源
      最近更新 更多