2012-01-30 11 views
10

Jaka jest różnica kiedy robięrubin self.class.class_eval lub singleton_class.class_eval

class T 

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

end 

i

class T 

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

end 

Thanks

PS. Tass odpowiedział, że w tym przykładzie singleton_class zwróci inny id_obiektu dla każdego nowego obiektu, ponieważ singleton_class należy do tylko jednego obiektu. Ale IRB pokazy obok

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

Nie mogę znaleźć żadnej różnicy funkcjonalnej, ale myślę, że powinna być jedna. –

+2

@JakubHampl, wygląda na to, że znalazłem różnicę) –

+1

@AlexKliuchnikau Wiedziałem, że ktoś by to zrobił. +1 do ciebie! –

Odpowiedz

10

Różnica między instancjami tych T klas jest w algorytmie metody przeglądowej: Metoda jest zawsze szukał w klasie singleton (i jego modułów) i tylko wtedy, gdy nie znajduje się tutaj, że jest poszukiwany w klasie .

To znaczy, jeśli dodamy metoda test do pierwszego wdrożenia klasy T po inicjalizacji otrzymamy inny wynik, niż gdy robimy to samo dla drugiej realizacji klasie 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

dzięki za odpowiedź! teraz widzę różnicę) – Fivell

+0

Z praktycznego punktu widzenia, kiedy zrobiłbyś jeden nad drugim? – Claw

+0

@Claw, powyższe metody to po prostu ciekawa próbka testowa, nie napisałbym czegoś takiego w inicjatorze prawdziwej klasy. Ogólnie: dodaj metody do * klasy *, gdy musisz dodać metodę do * wszystkich * wystąpień klasy i dodać metodę do * klasy singleton *, gdy musisz dodać metodę do * pojedynczego * wystąpienia klasy. W przykładzie 2 OP dodaje metodę do * klasy singleton * * każdej instancji * metody (w inicjalizatorze) - to nie jest praktyczne, dodaj metodę do * klasy * w takich sytuacjach. –

7

singleton_class daje Class który jest unikalny dla tego obiektu. self.class daje klasę, że wszystkie obiekty z tego Class akcji. 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 

W powyższym przykładzie singleton_class powróci inny object_id dla każdego nowego obiektu, ponieważ singleton_class należy tylko do jednego Object. self.class zwróci to samo, ponieważ self.class wskazuje za każdym razem ten sam numer Class.

+2

To wynika prawie bezpośrednio z dokumentów. Ale to nie jest odpowiedź na to pytanie. Jaka jest różnica między tymi dwoma podejściami w powyższym kodzie? –

+1

Wygląda na to, że OP nie pyta, jaka jest różnica między klasą i klasą singleton, ale jaka jest różnica między tymi dwoma przykładami, które dostarczył z punktu widzenia wykonania programu. W obu przypadkach wystąpienia 'T' będą miały instancję z metodą' test' i jak są różne? –

+0

dzięki za odpowiedź, Alex, jasne, chcę zrozumieć różnicę, o której wspomniałeś – Fivell