Answers:
某些类(例如标准库的套接字类)定义了自己的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__
在同一方法的两个别名,你可能会在第三感兴趣,somwhat不同的可能性,这是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。
__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)
最后,尝试使用public_send避免直接调用私有方法,而不要使用__send__或send。
__send__
,而没有send
。