回答:
一部のクラス(たとえば、標準ライブラリのソケットクラス)は、sendとは関係のない独自のメソッドを定義しObject#sendます。したがって、任意のクラスのオブジェクトを操作したい場合は、を使用__send__して安全を確保する必要があります。
今そこにある理由葉質問、それsendだけではありません__send__。のみがあった場合は__send__名前がsend混乱することなく、他のクラスで使用することができます。その理由は、つまりsend最初に存在していたとだけ後でそれは名前があることを実現したsendので、また有効他のコンテキストで使用される可能性があります__send__(で起こった同じことだと添加し、idそしてobject_id方法によって)。
public_send、それはsendとにかく多くの場合より好まれます。
本当にsend通常のように動作する必要がある場合は、__send__オーバーライドされない(すべきでない)ため、を使用する必要があります。__send__操作されているクラスがどのメソッドを定義しているかわからない場合、使用はメタプログラミングで特に役立ちます。オーバーライドされている可能性がありますsend。
見る:
class Foo
def bar?
true
end
def send(*args)
false
end
end
foo = Foo.new
foo.send(:bar?)
# => false
foo.__send__(:bar?)
# => true
をオーバーライドすると__send__、Rubyは警告を発します。
警告: `__send__ 'を再定義すると深刻な問題が発生する可能性があります
オーバーライドsendすることが役立つ場合は、メッセージパッシング、ソケットクラスなど、その名前が適切な場合です。
他の人がすでにあなたに言ったことsendと__send__、結局のところ、それが同じメソッドの2つのエイリアスであることを除けば、3番目のまったく異なる可能性であるに興味があるかもしれませんpublic_send。例:
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
更新:Ruby 2.1以降Module#include、Module#extendメソッドは公開されるため、上記の例は機能しなくなります。
send __send__、、およびpublic_send の主な違いは次のとおりです。
__send__はObjectのメソッドの呼び出しに使用されるものと同じですが、主な違いは、警告なしでsendメソッドをオーバーライドできることと、オーバーライド__send__すると警告メッセージが表示されることです。警告:再定義
__send__すると重大な問題が発生する可能性があります
これは、競合を回避するため、特にGemまたはライブラリで、使用されるコンテキストが不明な場合__send__に、送信ではなく常に使用するためです。
__send__)とpublic_sendの違いは、send / __send__はオブジェクトのプライベートメソッドを呼び出すことができ、public_sendは呼び出せないことです。class Foo
def __send__(*args, &block)
"__send__"
end
def send(*args)
"send"
end
def bar
"bar"
end
private
def private_bar
"private_bar"
end
end
Foo.new.bar #=> "bar"
Foo.new.private_bar #=> NoMethodError(private method 'private_bar' called for #Foo)
Foo.new.send(:bar) #=> "send"
Foo.new.__send__(:bar) #=> "__send__"
Foo.new.public_send(:bar) #=> "bar"
Foo.new.send(:private_bar) #=> "send"
Foo.new.__send__(:private_bar) #=> "__send__"
Foo.new.public_send(:private_bar) #=> NoMethodError(private method 'private_bar' called for #Foo)
最後に、__ send__またはsendを使用する代わりにpublic_sendを使用してプライベートメソッドの直接呼び出しを回避してください。
__send__、はありませんsend。