2012-01-30 2 views
10

Что разница, когда ярубин self.class.class_eval или singleton_class.class_eval

class T 

    def initialize 
    self.class.class_eval do 
     def test 
     return self.class.object_id 
    end 
    end 
    end 

end 

и

class T 

    def initialize 
    singleton_class.class_eval do 
     def test 
     return self.class.object_id 
    end 
    end 
    end 

end 

Благодарности

PS. Tass ответил, что в этом примере singleton_class вернет другой object_id для каждого нового объекта, потому что singleton_class принадлежит только одному объекту. Но IRB показывает следующий

1.9.2p180 :001 > class T 
1.9.2p180 :002?> 
1.9.2p180 :003 >  def initialize 
1.9.2p180 :004?>  singleton_class.class_eval do 
1.9.2p180 :005 >    def test 
1.9.2p180 :006?>     return self.class.object_id 
1.9.2p180 :007?>    end 
1.9.2p180 :008?>  end 
1.9.2p180 :009?>  end 
1.9.2p180 :010?> 
1.9.2p180 :011 >  end 
=> nil 
1.9.2p180 :012 > t = T.new 
=> #<T:0x00000100ae9cb8> 
1.9.2p180 :013 > t1 = T.new 
=> #<T:0x00000100ad7ef0> 
1.9.2p180 :014 > t1.test == t.test 
=> true 
1.9.2p180 :015 > t1.test 
=> 2153233300 
1.9.2p180 :016 > t.test 
=> 2153233300 
1.9.2p180 :017 > 
+1

Я не могу найти никакой функциональной разницы, но я думаю, что должен быть один. –

+2

@JakubHampl, похоже, я нашел разницу) –

+1

@AlexKliuchnikau Я знал, что кто-то будет. +1 к вам! –

ответ

10

Разница между экземплярами этих T классов в алгоритме метода поиска: метод всегда ищется в классе одноплодной (и его модули), и только если он не будет найден здесь, он ищется в классе.

Это значит, если мы добавим метод test к первой реализации класса T после инициализации мы получим другой результат, чем когда мы делаем то же самое для второй реализации класса T:

# First example 
class T 
    def initialize 
    self.class.class_eval do 
     def test 
     return self.class.object_id 
     end 
    end 
    end 
end 

t = T.new 

class T 
    def test 
    'overriden' 
    end 
end 

puts t.test # => 'overriden' 

class T 
    def initialize 
    singleton_class.class_eval do 
     def test 
     return self.class.object_id 
     end 
    end 
    end 
end 

t = T.new 

class T 
    def test 
    'overriden' 
    end 
end 

puts t.test # => 77697390 
+0

спасибо, что ответь! теперь я вижу разницу) – Fivell

+0

С практической точки зрения, когда вы делаете одно над другим? – Claw

+0

@Claw, методы выше - просто любопытные тестовые образцы, я бы не писал ничего подобного в инициализаторе реального класса. Как правило: добавьте методы в класс *, когда вам нужно добавить метод к * всем * экземплярам класса и добавить метод к * singleton class *, когда вам нужно добавить метод к * одиночному экземпляру класса. В примере 2 OP добавляет метод к * singleton class * экземпляра * each * метода (в инициализаторе) - это нецелесообразно, добавьте метод в * класс * в таких ситуациях. –

7

singleton_class дает Class, который является уникальным для этого объекта. self.class дает вам класс, что все объекты этого Class share. Example

foobar = Array.new 

# this defines a method on the singleton class 
def foobar.size 
    "Hello World!" 
end 

foobar.size # => "Hello World!" 
foobar.class # => Array 

bizbat = Array.new 
bizbat.size # => 0 

В приведенном выше примере, singleton_class будет возвращать различные object_id для каждого нового объекта, поскольку singleton_class принадлежит только одному Object. self.class вернет то же самое, потому что self.class действительно указывает на то же самое Class каждый раз.

+2

Это следует прямо из документов. Но это не ответ на вопрос. Какая разница между этими двумя подходами в коде выше? –

+1

Похоже, что OP не спрашивает, в чем разница между классом и классом singleton, но в чем разница между этими двумя примерами, которые он предоставил с точки зрения выполнения программы. В обоих случаях экземпляры 'T' будут иметь экземпляр с методом' test' и как они отличаются? –

+0

спасибо за ответ, Алекс, конечно, я хочу понять разницу, о которой вы упомянули – Fivell