Подсчет инициализаций класса Ruby

Есть ли способ подсчитать количество экземпляров, созданных во время работы программы?

Что-то вроде

class Foo      
    @bar = 0

    def initialize
        @bar += 1
    end
end

не будет работать (@bar это nil в initialize).

Это можно как-то сделать?


person Nicolas Scherer    schedule 27.08.2015    source источник
comment
См. это: stackoverflow.com/questions/16794896/   -  person tomsoft    schedule 27.08.2015
comment
Вас волнуют заброшенные инстансы и выброшенный мусор?   -  person Cary Swoveland    schedule 27.08.2015


Ответы (2)


Переменные экземпляра принадлежат объектам (экземплярам), поэтому они все-таки называются переменными экземпляра. Ваш первый @bar является переменной экземпляра Foo, ваш второй @bar является переменной экземпляра только что созданного экземпляра Foo. Это два совершенно разных объекта (они даже не одного класса: только что созданный экземпляр относится к классу Foo, а Foo — к классу Class).

Очевидно, вам нужно увеличить @bar в методе, вызываемом для Foo, а не в методе, вызываемом для экземпляров Foo. Итак, можем ли мы подумать о методе, который а) вызывается Foo и б) вызывается каждый раз при создании экземпляра? А как насчет new?

class Foo
  @bar = 0

  def self.new(*)
    @bar += 1
    super
  end
end

Хорошо, с технической точки зрения, здесь не учитывается количество экземпляров, а только количество вызовов new. Иногда экземпляры создаются без вызова new, например. при десериализации. Это должно быть самое близкое, что вы можете получить, не прибегая к уродливым хакам внутренностей интерпретатора.

Вы можете подумать, что вместо этого можно переопределить allocate (я тоже так думал), но я только что проверил это, и это не работает. Предположительно, реализация new по умолчанию не вызывает allocate обычными средствами, а фактически напрямую использует внутреннюю реализацию интерпретатора.

person Jörg W Mittag    schedule 27.08.2015

Вы должны использовать переменную класса вместо переменной экземпляра:

class Foo
  @@count = 0
  def initialize
    @@count += 1
  end

  def Foo.get_count
    @@count
  end
end

foo1 = Foo.new
foo2 = Foo.new
foo3 = Foo.new

puts Foo.get_count
# => 3
person Yu Hao    schedule 27.08.2015
comment
Спасибо за Ваш ответ. Ну, этот пример действительно работает, но для меня это не решение, так как мне нужно подсчитать экземпляры трех классов, которые расширяют один модуль. Я не могу понять, как использовать это как переменную класса в модуле. - person Nicolas Scherer; 27.08.2015