2011-01-11 114 views
137

我理解some_instance.send的概念,但我試圖弄清楚爲什麼你可以這樣調用這兩種方式。 Ruby Koans暗示除了提供很多不同的方法來做同樣的事情之外,還有一些原因。以下是兩種使用示例:紅寶石發送vs __send__

class Foo 
    def bar? 
    true 
    end 
end 

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

任何人對此有什麼想法?

回答

213

某些類(例如標準庫的套接字類)定義了自己的send方法,它與Object#send無關。所以如果你想使用任何類的對象,你需要使用__send__來保證安全。

現在留下了問題,爲什麼有send而不僅僅是__send__。如果只有__send__,則名稱send可以被其他類別使用而不會造成任何混淆。其原因是,send存在第一,只是後來人們意識到,該名send也可能有益地在其他情況下使用,因此加入__send__(這是由用方式和id發生object_id同樣的事情)。

+7

此外,[BasicObject](http://ruby-doc.org/core/BasicObject.html)(在Ruby 1.9中引入)只有`__send__`,而不是`send`。 – 2014-08-10 23:50:31

+0

很好的答案。可能會更好,如果它提到`public_send`,這通常比`send`更適合。 – 2016-03-04 00:48:39

29

如果你真的需要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__,紅寶石會發出警告:

警告:重新定義`__send__」可能 導致嚴重問題

某些情況下,覆蓋send將會是合適的名稱,比如message pas唱歌,插座類等

9

__send__存在,所以它不能被意外覆蓋。

至於爲什麼send存在:我不能代表任何人說話,但object.send(:method_name, *parameters)看起來比object.__send__(:method_name, *parameters)更好,所以我用send,除非我需要使用__send__

5

除了別人已經告訴你,什麼歸結爲說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 

更新:由於紅寶石2.1,Module#includeModule#extend方法成爲公共的,所以上面的例子將不再工作。