2012-12-06 13 views
10

के भीतर फ़ंक्शन क्यों नीचे कोड स्निपेट foo इसकी परिभाषा को प्रतिस्थापित करता है?क्यों foo अब शून्य नहीं है - या फ़ंक्शन

foo 
=> 1 

आप foo देख सकते हैं अब और नहीं के बराबर नहीं है:

def foo 
    def foo 
    1 
    end 
end 

पहली बार foo के लिए

अगर मैं foo फिर से फोन नहीं के बराबर

foo 
=> nil 

foo.foo 
=> 1 

है अब। क्या कोई मुझे ये समझा सकता है? धन्यवाद।

उत्तर

6
def foo 
    p "about to redef foo" 
    def foo 
    1 
    end 
end 
foo 
"about to redef foo" 
=> nil 
foo 
=> 1 

इसके अलावा, जब आप foo.foo कहते हैं, यह आप की तरह भीतरी foo विधि का उपयोग करने की कोशिश कर रहे हैं लगता है, लेकिन यह उस तरह काम नहीं करता। आपकी foo विधि वास्तव में Object पर परिभाषित की गई है, इसलिए आप वास्तव में 1.foo पर कॉल कर रहे हैं।

0

अपना पहला कॉल foo यह विधि foo वापस आती है और जब आप फिर से foo फोन वापस करती 1. पढ़ें closure

+0

असल में यह पहली बार शून्य आता है, बी/सी रूबी प्रथम श्रेणी के तरीकों का समर्थन नहीं करता है (इस अर्थ में कम से कम)। तो कोई विधि वस्तु वापस नहीं आती है। – trans

1

आप इस प्रभाव चाहते हैं,

def foo 
    foo = proc { 
    1 
    } 
end 

के बाद से def तरीकों का निर्माण नहीं करतीं का प्रयास करते हैं एक नया self। प्रत्येक विधि से self पर है, जो इस मामले में main है, एक ऑब्जेक्ट.न्यू रूबी दुभाषिया द्वारा लोड की गई प्रत्येक फ़ाइल के लिए तत्काल है। कक्षा के अंदर, self कक्षा है, और आपको इंस्टेंस विधियां मिलती हैं।

+0

असाइनमेंट की आवश्यकता नहीं है। – akuhn

+0

वह किसी अन्य नामस्थान के भीतर foo चाहता है, लेकिन हाँ, फ़ंक्शन बस एक ब्लॉक लौटाता है। – Reactormonk

1

पढ़ाई के दौरान विधि परिभाषाओं को पार्स किया जाता है, लेकिन जब तक कॉल नहीं किया जाता है तब तक निष्पादित नहीं किया जाता है। जब आप पहली बार foo करते हैं, सबसे बाहरी foo निष्पादित किया जाता है, जो Object#foo रूप

def foo 
    1 
end 

परिभाषित करता है और एक ऑपरेशन विधि परिभाषित कि की वापसी मान के रूप में nil देता है। तब से, जब आप foo, फोन नव परिभाषित foo निष्पादित किया जाता है, लौटने

1 
0

माणिक में नेस्टेड विधि परिभाषाओं भ्रमित कर रहे हैं।

वे वास्तव में redefinitions हैं!

क्या होता है कि दोनों परिभाषाएं बाहरी संदर्भ पर लागू होती हैं। यह दोनों परिभाषाएं एक ही (!) विधि foo को परिभाषित करती हैं। हालांकि बाहरी परिभाषा का अर्थ तब होता है जब फ़ाइल पढ़ी जाती है, जबकि आंतरिक परिभाषा का अर्थ केवल तभी किया जाता है जब बाहरी विधि को पहली बार बुलाया जाता है। इसके बाद यह प्रारंभिक परिभाषा को प्रतिस्थापित करेगा।

इस कोड

def foo 
    def foo 
    1 
    end 
end 

चलो इस के माध्यम से चलना चलो देखते हुए:

  1. जब आपकी फ़ाइल एक वैश्विक विधि foo लोड हो रहा है शरीर def foo; 1; end साथ परिभाषित किया गया है।
  2. जब आप foo() फोन इस वैश्विक विधि मार डाला जाता है और वैश्विक विधिfoo को पुनर्परिभाषित शरीर 1 के साथ, और nil रिटर्न के बाद से एक विधि को परिभाषित कोई वापसी मूल्य है।

  3. जब आप कॉल foo().foo() वैश्विक विधि मार डाला और 1, जिस पर वैश्विक विधि फिर से क्रियान्वित किया जाता है देता है, 1 फिर से लौट रहा है।

यहाँ भ्रामक दो बातें, एक) है कि नेस्टेड विधि परिभाषा दोनों एक ही बाहरी गुंजाइश के लिए लागू करते हैं और ख) एक वैश्विक विधि किसी भी वस्तु पर कहा जा सकता है कि कर रहे हैं।

यह दिखाने के लिए एक और उदाहरण है कि कैसे नेस्टेड परिभाषा वास्तव में परिभाषाओं को परिभाषित करती है।

class A 
    def m(arg=nil) 
    def m; 42; end if arg 
    23 
    end 
end 

यहाँ क्या होता है

a = A.new 
a.m # => 23 
a.m # => 23 
a.m(:magic) # => 23 
a.m # => 42 
a.m # => 42 

के रूप में आप देख सकते हैं, नेस्टेड परिभाषा वास्तव में एक नई परिभाषा है।

0

व्यक्तिगत रूप से मैंने हमेशा यह बहुत अजीब सोचा कि यह कक्षा में आंतरिक def परिभाषित करता है। मुझे लगता है कि इसे सिंगलटन पर परिभाषित करना अधिक समझदार होगा। जैसे def self.foo के बराबर, क्योंकि इसे आवृत्ति स्तर पर कहा जा रहा है, न कि वर्ग स्तर पर।

या तो, या यह केवल उस विधि से कॉल करने योग्य हो सकता है जिसे परिभाषित किया गया है - हालांकि यह हमारे लिए लैम्बडास के रूप में उपयोगी नहीं हो सकता है।

हालांकि कुछ बात निश्चित है, आप इसे अभ्यास में लगभग कभी नहीं देख पाएंगे।

संबंधित मुद्दे