回答:
一部のクラス(たとえば、標準ライブラリのソケットクラス)は、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
。