रूबी भेजें __send__


151

मैं इस अवधारणा को समझता हूं, some_instance.sendलेकिन मैं यह जानने की कोशिश कर रहा हूं कि आप इसे दोनों तरीकों से क्यों कह सकते हैं। रूबी कोन्स का अर्थ है कि एक ही काम करने के लिए बहुत सारे अलग-अलग तरीके प्रदान करने से परे कुछ कारण है। यहाँ उपयोग के दो उदाहरण दिए गए हैं:

class Foo
  def bar?
    true
  end
end

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

किसी को भी इस बारे में कोई विचार है?

जवाबों:


242

कुछ कक्षाएं (उदाहरण के लिए मानक पुस्तकालय की सॉकेट क्लास) अपनी स्वयं की sendविधि को परिभाषित करती हैं जिसका कोई लेना-देना नहीं है Object#send। इसलिए यदि आप किसी भी वर्ग की वस्तुओं के साथ काम करना चाहते हैं, तो आपको __send__सुरक्षित तरफ रहने के लिए उपयोग करने की आवश्यकता है ।

अब यह सवाल छोड़ देता है कि क्यों sendऔर क्या नहीं है __send__। यदि केवल __send__नाम थे तो sendअन्य वर्गों द्वारा बिना किसी भ्रम के उपयोग किया जा सकता है। उस के लिए कारण यह है कि है sendपहले से ही अस्तित्व में है और केवल बाद में यह महसूस किया गया कि नाम sendहै, इसलिए भी उपयोगी अन्य संदर्भों में इस्तेमाल किया जा सकता __send__जोड़ा गया है (है कि एक ही बात यह है कि के साथ हुआ है idऔर object_idजिस तरह से)।


8
इसके अलावा, BasicObject (रूबी 1.9 में पेश) केवल है __send__, नहीं send
एंड्रयू मार्शल

अच्छा उत्तर। यदि यह उल्लेख किया जाए तो और भी बेहतर हो सकता है public_send, जो अक्सर किसी भी तरह से बेहतर होता है send
मार्क-आंद्रे लाफोर्टिन

31

यदि आपको वास्तव में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होगा, जहां वह नाम उचित होगा, जैसे संदेश गुजरना, सॉकेट कक्षाएं, आदि।


9

__send__ मौजूद है इसलिए यह दुर्घटना से अधिक नहीं लिखा जा सकता है।

जैसे कि क्यों sendमौजूद है: मैं किसी और के लिए नहीं बोल सकता, लेकिन इससे object.send(:method_name, *parameters)अच्छा लग रहा है object.__send__(:method_name, *parameters), इसलिए मैं sendतब तक उपयोग करता हूं जब तक मुझे उपयोग करने की आवश्यकता नहीं है __send__


6

इसके अलावा दूसरों ने आपको जो पहले ही बताया था, और जो यह कहते हुए उबलता है 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

अपडेट: चूंकि रूबी 2.1, Module#includeऔर Module#extendविधियां सार्वजनिक हो जाती हैं, इसलिए उपरोक्त उदाहरण अब काम नहीं करेगा।


0

भेजें __send__, और public_send के बीच मुख्य अंतर निम्नानुसार है।

  1. भेजें और __send__तकनीकी रूप से उसी तरह हैं जैसे कि ऑब्जेक्ट की विधि को कॉल करने के लिए उपयोग किया जाता है, लेकिन मुख्य अंतर यह है कि आप किसी भी चेतावनी के बिना भेजने की विधि को ओवरराइड कर सकते हैं और जब आप ओवरराइड करते हैं __send__तब एक चेतावनी संदेश होता है

चेतावनी: पुनर्परिभाषित करने से __send__गंभीर समस्याएं हो सकती हैं

इसका कारण यह है कि संघर्ष से बचने के लिए, विशेष रूप से रत्नों या पुस्तकालयों में जब संदर्भ जहां इसका उपयोग किया जाएगा वह अज्ञात है, हमेशा __send__भेजने के बजाय उपयोग करें ।

  1. सेंड (या __send__) और public_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__ या भेजने के बजाय निजी विधि से सीधे कॉल से बचने के लिए public_send का उपयोग करने का प्रयास करें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.