2011-01-11 10 views
137

私はsome_instance.sendのコンセプトを理解していますが、私はこれを両方の方法で呼び出すことができる理由を理解しようとしています。 Ruby Koansは、同じことをするためのさまざまな方法を提供する以外にも何らかの理由があることを暗示しています。ここに2つの使用例があります:Ruby send vs __send__

class Foo 
    def bar? 
    true 
    end 
end 

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

誰でもこのことについてご意見がありますか?

答えて

213

Object#sendとは何の関係もない独自のsendメソッドを定義するクラス(標準ライブラリのソケットクラスなど)があります。したがって、クラスのオブジェクトで作業したい場合は、安全面には__send__を使用する必要があります。

ここでは、sendがあり、なぜ__send__ではないのかという疑問が残ります。 __send__しかない場合は、他のクラスで混乱することなくsendという名前を使用できます。その理由は、最初にsendが存在し、後で名前sendが他のコンテキストでも有効に使用される可能性があることに気づいたので、__send__が追加されました(これはidobject_idで起こったのと同じことです)。

+7

また、[BasicObject](http://ruby-doc.org/core/BasicObject.html)(Ruby 1.9で導入)には 'send'ではなく' __send__'しかありません。 –

+0

良い答え。それが 'public_send'と言えば、さらに良いかもしれません。 –

29

あなたが本当にそれは通常、あなたが__send__を使用する必要があるんだろうように、それが(それはないはず)上書きされることはありませんので、動作するsendが必要な場合。 __send__を使用すると、操作中のクラスがどのようなメソッドを定義しているのかわからないときに、メタプログラミングで特に便利です。それはsendをオーバーライドした可能性があります。

ウォッチ:

警告:あなたは__send__をオーバーライドする場合、Rubyは警告発します

class Foo 
    def bar? 
    true 
    end 

    def send(*args) 
    false 
    end 
end 

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

`__send__」再定義をしてもよい 原因深刻な問題

いくつかの例sendをオーバーライドすると便利です。メッセージパースのような、その名前が適切な場所になるでしょう。

9

__send__が存在するため、偶然に上書きすることはできません。

sendが存在する理由については

:私は誰のために話すことはできませんが、object.send(:method_name, *parameters)object.__send__(:method_name, *parameters)より立派に見えるので、私は__send__を使用するが必要ない限り、私はsendを使用しています。別に他の人がすでにあなたに言った、と何send__send__が同じ方法の2つのエイリアスである、あなたはpublic_sendである第三、somwhat異なる可能性、に興味があるかもしれないと言ってつまるところ何から

5

。例:

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 

更新:上記の例はもう働かないようにルビー2.1、Module#includeModule#extend方法は、パブリックになるので。

+0

良い知識、ありがとう! – jaydel