2011-02-01 13 views
69

मेरे पास एक विधि के अंदर एक विधि है। आंतरिक विधि एक चर लूप पर निर्भर करता है जो चल रहा है। क्या यह एक बुरा विचार है?क्या तरीकों के अंदर तरीके होना संभव है?

+1

क्या आप कोड नमूना या कम से कम एक तार्किक समकक्ष साझा कर सकते हैं जो आप करने की कोशिश कर रहे हैं। –

उत्तर

135

अपडेट: चूंकि इस उत्तर में हाल ही में कुछ रूचि मिली है, इसलिए मैं यह इंगित करना चाहता हूं कि discussion on the Ruby issue tracker to remove the feature discussed here, namely to forbid having method definitions inside a method body है।


नहीं, रुबी में घोंसला वाले तरीके नहीं हैं।

आप कुछ इस तरह कर सकते हैं:

class Test1 
    def meth1 
    def meth2 
     puts "Yay" 
    end 
    meth2 
    end 
end 

Test1.new.meth1 

लेकिन उस नहीं एक नेस्टेड तरीका है। मैं दोहराना: रूबी में नेस्टेड विधियां नहीं हैं I

यह क्या है, गतिशील विधि परिभाषा है। जब आप meth1 चलाते हैं, तो meth1 का निकाय निष्पादित किया जाएगा। शरीर meth2 नामक एक विधि को परिभाषित करने के लिए होता है, यही कारण है कि meth1 एक बार चलाने के बाद, आप meth2 पर कॉल कर सकते हैं।

लेकिन meth2 कहां है? खैर, यह स्पष्ट रूप से को नेस्टेड विधि के रूप में परिभाषित किया गया है, क्योंकि रूबी में नेस्टेड विधियां नहीं हैं। यह Test1 का एक उदाहरण विधि के रूप में परिभाषित किया है:

Test1.new.meth2 
# Yay 

इसके अलावा, यह स्पष्ट रूप से हर बार जब आप meth1 चलाने नए सिरे से परिभाषित किया जाएगा:

Test1.new.meth1 
# Yay 

Test1.new.meth1. 
# test1.rb:3: warning: method redefined; discarding old meth2 
# test1.rb:3: warning: previous definition of meth2 was here 
# Yay 

संक्षेप में: कोई, रूबी नहीं समर्थन नेस्ट तरीकों से करता है।

ध्यान दें कि रूबी में, विधि निकायों को बंद नहीं किया जा सकता है, केवल ब्लॉक निकायों ही कर सकते हैं। यह बहुत अधिक नेस्टेड विधियों के लिए प्रमुख उपयोग केस को समाप्त करता है, क्योंकि यदि रूबी नेस्टेड विधियों का समर्थन किया है, तो आप नेस्टेड विधि में बाहरी विधि के चर का उपयोग नहीं कर सके।


अद्यतन जारी रखा: एक बाद में चरण में है, तो, इस वाक्य रूबी से नेस्टेड विधियों, जो जिस तरह से मैं वर्णित व्यवहार करते हैं जोड़ने के लिए फिर से इस्तेमाल किया जा सकता है: वे अपने युक्त विधि के दायरे वाला की जाएगी यानी उनके युक्त विधि निकाय के बाहर अदृश्य और पहुंच योग्य। और संभवतः, उनके पास उनके युक्त विधि के व्याख्यात्मक दायरे तक पहुंच होगी। हालांकि, अगर आप उपर्युक्त चर्चा को पढ़ते हैं, तो आप देख सकते हैं कि मैट नेस्टेड विधियों के खिलाफ भारी है (लेकिन अभी भी नेस्टेड विधि परिभाषाओं को हटाने के लिए)।

+6

हालांकि, आप यह भी दिखा सकते हैं कि ड्रवाईनेस के लिए एक विधि में बंद लैम्ब्डा कैसे बनाना है, या रिकर्सन चलाने के लिए। – Phrogz

+100

मुझे यह महसूस हो रहा है कि रूबी में घोंसला वाले तरीके नहीं हो सकते हैं। –

+11

@ मार्क थॉमस: क्या मैं यह उल्लेख करना भूल गया कि रूबी नेस्टेड तरीकों को नहीं बचाया है? :-) गंभीरता से: जब मैंने यह उत्तर लिखा था, वहां पहले से ही तीन उत्तर थे, जिनमें से हर एक ने दावा किया था कि रुबी * ने नेस्टेड विधियों को किया है। उन उत्तरों में से कुछ ने भी गलत तरीके से गलत होने के बावजूद अपवित्र किया था। गलत होने के बावजूद ओपी ने फिर भी इसे स्वीकार किया था। कोड स्निपेट जो उत्तर देने के लिए उपयोग करता है यह साबित करने के लिए उपयोग करता है कि रूबी नेस्टेड विधियों का समर्थन करता है, वास्तव में विपरीत साबित करता है, लेकिन स्पष्ट रूप से न तो अपवित्र और न ही ओपी वास्तव में जांच करने के लिए परेशान है। इसलिए, मैंने हर गलत के लिए एक सही जवाब दिया। :-) –

4

नहीं, नहीं, रूबी ने घोंसले के तरीके हैं।इस जाँच करें:

def outer_method(arg) 
    outer_variable = "y" 
    inner_method = lambda { 
     puts arg 
     puts outer_variable 
    } 
    inner_method[] 
end 

outer_method "x" # prints "x", "y" 
+4

inner_method एक विधि नहीं है, यह एक फ़ंक्शन/लैम्ब्डा/proc है। किसी भी वर्ग का कोई संबद्ध उदाहरण नहीं है, इसलिए यह एक विधि नहीं है। –

-1

:-D

रूबी तरीकों नेस्ट गया है, केवल वे तुम्हें उम्मीद थी कि उनके साथ क्या

1.9.3p484 :001 > def kme; 'kme'; def foo; 'foo'; end; end    
=> nil 
1.9.3p484 :003 > self.methods.include? :kme 
=> true 
1.9.3p484 :004 > self.methods.include? :foo 
=> false 
1.9.3p484 :005 > kme 
=> nil 
1.9.3p484 :006 > self.methods.include? :foo 
=> true 
1.9.3p484 :007 > foo 
=> "foo" 
+3

यह नेस्टेड विधि नहीं है ... देखें * स्पष्ट समझ के लिए जोर्ग डब्ल्यू मिट्टाग * का जवाब। – Hardik

1

आप इस

की तरह कुछ कर सकते हैं मत करो
module Methods 
    define_method :outer do 
    outer_var = 1 
    define_method :inner do 
     puts "defining inner" 
     inner_var = outer_var +1 
    end 
    outer_var 
    end 
    extend self 
end 

Methods.outer 
#=> defining inner 
#=> 1 
Methods.inner 
#=> 2 

यह उपयोगी है जब आप डीएसएल लिखने जैसी चीजें कर रहे हैं जिसके लिए विधियों के बीच दायरे को साझा करने की आवश्यकता होती है। लेकिन अन्यथा, आप कुछ और करने से बेहतर हैं, क्योंकि अन्य उत्तरों ने कहा है कि inner को फिर से परिभाषित किया जाता है जब भी outer आक्रमण किया जाता है। यदि आप यह व्यवहार चाहते हैं, और आप कभी-कभी ऐसा कर सकते हैं, तो इसे प्राप्त करने का यह एक अच्छा तरीका है।

9

वास्तव में यह संभव है। आप इसके लिए procs/lambda का उपयोग कर सकते हैं।

def test(value) 
    inner = ->() { 
    value * value 
    } 
    inner.call() 
end 
0

रूबी तरह से नकली यह भ्रामक हैक्स जबकि कम उत्सुक बस वाक्य रचना बात का उपयोग करने के लिए आवश्यक याद होगा कुछ उपयोगकर्ताओं, "बकवास में करता है यह कैसे भी काम?" सोच रहा होगा कि साथ है। यदि आपने कभी रेक या रेल का उपयोग किया है, तो आपने इस तरह की चीज़ देखी है।

यहाँ इस तरह के एक हैक है:

def mlet(name,func) 
    my_class = (Class.new do 
       def initialize(name,func) 
        @name=name 
        @func=func 
       end 
       def method_missing(methname, *args) 
        puts "method_missing called on #{methname}" 
        if methname == @name 
        puts "Calling function #{@func}" 
        @func.call(*args) 
        else 
        raise NoMethodError.new "Undefined method `#{methname}' in mlet" 
        end 
       end 
       end) 
    yield my_class.new(name,func) 
end 

क्या करता है एक उच्च-स्तरीय विधि है कि एक वर्ग पैदा करता है और एक ब्लॉक को पास कर देता परिभाषित है। कक्षा method_missing का उपयोग करने का दावा करती है कि आपके द्वारा चुने गए नाम के साथ एक विधि है। यह आपको प्रदान किए जाने वाले लैम्ब्डा को कॉल करके विधि को "लागू करता है"। किसी एक अक्षर के नाम के साथ ऑब्जेक्ट का नामकरण करके, आप अतिरिक्त टाइपिंग की मात्रा को कम कर सकते हैं (जो वही है जो रेल schema.rb में करता है)। mlet का नाम आम लिस्प फॉर्म flet के नाम पर रखा गया है, सिवाय इसके कि f "फ़ंक्शन" के लिए खड़ा है, m "विधि" के लिए खड़ा है।

आप इस तरह इसका इस्तेमाल:

def outer 
    mlet :inner, ->(x) { x*2 } do |c| 
    c.inner 12 
    end 
end 

यह एक समान कोंटरापशन कि अतिरिक्त नेस्टिंग बिना परिभाषित किया जा करने के लिए कई भीतरी कार्यों के लिए अनुमति देता है बनाने के लिए संभव है, लेकिन हो सकता है कि आप एक तरह से एक और भी भद्दा हैक की आवश्यकता है रेक या रुपेक के कार्यान्वयन में खोजें। यह पता लगाने के लिए कि कैसे रुपयेपी let! काम आपको इस तरह के एक भयानक घृणा को बनाने में सक्षम होने के लिए एक लंबा सफर तय करेंगे।

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