Ruby发送vs __send__
我理解some_instance.send
的概念,但我试图弄清楚为什么你可以调用这两种方式。 Ruby Koans暗示,除了提供很多不同的方法来做同样的事情之外,还有一些原因。 以下是使用的两个例子:
class Foo def bar? true end end foo = Foo.new foo.send(:bar?) foo.__send__(:bar?)
任何人有任何想法呢?
有些类(例如标准库的套接字类)定义了自己的send
方法,这与Object#send
无关。 所以如果你想使用任何类的对象,你需要使用__send__
来保证安全。
现在留下了这个问题,为什么有send
,而不仅仅是__send__
。 如果只有__send__
, send
的名字可以被其他类使用,不会有任何混淆。 之所以这样,是因为send
是先存在的,后来才意识到send
的名字也可能用在其他的上下文中,所以__send__
被添加了(这与id
和object_id
的方式是一样的)。
如果你真的需要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
存在:我不能说任何人,但object.send(:method_name, *parameters)
看起来比object.__send__(:method_name, *parameters)
更好object.__send__(:method_name, *parameters)
,所以我使用send
除非我需要使用__send__
。
除了别人已经告诉过你的话,可以归结为send
和__send__
是同一个方法的两个别名,你可能会对第三个有些不同的可能性是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
方法变成公共的,所以上面的例子不再工作了。