2013-05-11 3 views
1

Я пишу модуль с методом foo, который вызывает метод класса bar в классе получателя. Мой текущий подход заключается в использовании self.class.bar, который прекрасно работает, если метод класса не определен в классе экземпляра, а не «реальный» один:Проверьте, имеет ли объект одноэлементный класс

module M 
    def foo 
    self.class.bar 
    end 
end 

obj = Object.new 
class << obj 
    include M 
    def self.bar 
    42 
    end 
end 

obj.foo # => NoMethodError: undefined method `bar' for Object:Class 

Это имеет смысл, потому что obj.class не возвращает одноэлементных классов. Я мог использовать obj.singleton_class вместо этого, и все будет работать бесперебойно:

module M 
    def foo 
    self.singleton_class.bar 
    end 
end 

obj = Object.new 
class << obj 
    include M 
    def self.bar 
    42 
    end 
end 

obj.foo # => 42 

только если метод определен на одноплодный класс по той же причине, что и выше. Хуже того, он создает новый одноэлементный класс для каждого получателя, чего я хочу избежать, поскольку это может быть довольно много объектов. Поэтому вместо этого я хочу каким-то образом получить одноэлементный класс объекта тогда и только тогда, когда уже определен, то есть что-то типа obj.has_singleton_class ? obj.singleton_class : obj.class. Однако я не мог найти способ выполнить эту проверку.

ответ

5

Каждый объект всегда имеет одноэлементный класс в Ruby. Конкретная реализация, которую вы используете (MRI, YARV, Rubinius, JRuby, IronRuby, MacRuby, MagLev, MRuby и т. Д.), Может или не может оптимизировать использование памяти, не выделяя память для одноэлементного класса, который не используется, но это частный внутренняя реализация, невидимая прозрачная оптимизация компилятора. Всякий раз, когда вы идете на одноэлементный класс, он будет там.

Ну, на самом деле, это не довольно true. Непосредственные значения, т.е. Integer s, Symbol s и Float s не могут имеют одноэлементные классы.

Таким образом, те три будут никогда имеют одноэлементный класс, все остальные всегда есть класс одноплодной.

+0

Этот ответ нуждался в обновлении, так как 'Fixnum' устарел в Ruby 2.4. См. [Этот ответ] (http://stackoverflow.com/a/21411269/513951) by @ JörgWMittag;) –

Смежные вопросы