2011-01-11 16 views
137

Rozumiem koncepcję some_instance.send, ale staram się dowiedzieć, dlaczego można nazwać to w obie strony. Ruby Koans sugerują, że jest jakiś powód, poza oferowaniem wielu różnych sposobów robienia tego samego. Oto dwa przykłady użycia:Ruby wysłać vs __send__

class Foo 
    def bar? 
    true 
    end 
end 

foo = Foo.new 
foo.send(:bar?) 
foo.__send__(:bar?) 

Ktoś ma jakiś pomysł na ten temat?

Odpowiedz

213

Niektóre klasy (na przykład klasa gniazda biblioteki standardowej) definiują własną metodę send, która nie ma nic wspólnego z Object#send. Więc jeśli chcesz pracować z obiektami dowolnej klasy, musisz użyć __send__, aby być po bezpiecznej stronie.

Teraz pozostawia pytanie, dlaczego istnieje send, a nie tylko __send__. Jeśli było tylko __send__, nazwa send mogła być używana przez inne klasy bez żadnego zamieszania. Powodem jest to, że send istniało w pierwszej kolejności i dopiero później okazało się, że nazwa send może być użytecznie użyta w innych kontekstach, więc dodano to samo, co id i object_id.

+7

Ponadto [BasicObject] (http://ruby-doc.org/core/BasicObject.html) (wprowadzone w Ruby 1.9) ma tylko '__send__', a nie' send'. –

+0

Dobra odpowiedź.Może być jeszcze lepiej, jeśli wspomniano o 'public_send', który jest często lepszy niż" wyślij "w każdym razie. –

29

Jeśli naprawdę trzeba send zachowywać się jak to zwykle zrobić, należy użyć __send__, ponieważ nie będzie (nie powinien) być nadpisane. Używanie __send__ jest szczególnie użyteczne w metaprogramowaniu, gdy nie wiesz, jakie metody definiuje klasa, która jest manipulowana. Mogło to przesłonić send.

Watch:

class Foo 
    def bar? 
    true 
    end 

    def send(*args) 
    false 
    end 
end 

foo = Foo.new 
foo.send(:bar?) 
# => false 
foo.__send__(:bar?) 
# => true 

Jeśli zastąpić __send__, Ruby wyemituje ostrzeżenie:

ostrzegawczy: przedefiniowujący `__send__” może przyczyną poważnych problemów

niektórych przypadkach, gdy byłoby użyteczne zastąpienie send byłoby tam, gdzie ta nazwa jest odpowiednia, jak wiadomość pas śpiewać, klasy gniazd itp.

9

__send__ istnieje, więc nie można go przepracować przez przypadek.

Jak, dlaczego send istnieje: Nie mogę mówić za kogoś innego, ale object.send(:method_name, *parameters) wygląda ładniej niż object.__send__(:method_name, *parameters), więc używam send chyba muszę używać __send__.

5

Oprócz tego, co inni już mówiłem, a co sprowadza się do stwierdzenia, że ​​send i __send__ dwa aliasy tej samej metody, może być zainteresowany w trzecim, somwhat inną możliwość, która jest public_send. Przykład:

A, B, C = Module.new, Module.new, Module.new 
B.include A #=> error -- private method 
B.send :include, A #=> bypasses the method's privacy 
C.public_send :include, A #=> does not bypass privacy 

Aktualizacja: Ponieważ Ruby 2.1, Module#include i Module#extend metody stają się publiczne, więc powyższy przykład nie będzie już działać.

+0

dobra znajomość, dzięki! – jaydel