2014-05-21 7 views
5

मैं समझने के साथ थोड़ा सा संघर्ष करता हूं कि Enumerator.new विधि कैसे काम करती है। प्रलेखन से उदाहरण मान लिया जाये:ब्लॉक के साथ Enumerator.new कैसे काम करता है?

fib = Enumerator.new do |y| 
    a = b = 1 
    loop do 
    y << a 
    a, b = b, a + b 
    end 
end 

p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] 

कहाँ पाश तोड़ हालत, यह कैसे जान लेता है कि है कि कितनी बार पाश दोहराना चाहते चाहिए (क्योंकि यह किसी भी स्पष्ट तोड़ हालत नहीं है और अनंत लूप तरह दिखता है)?

उत्तर

4

Enumerator आंतरिक Fibers उपयोग करता है। आपका उदाहरण इसके बराबर है:

require 'fiber' 

fiber = Fiber.new do 
    a = b = 1 
    loop do 
    Fiber.yield a 
    a, b = b, a + b 
    end 
end 

10.times.map { fiber.resume } 
#=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] 
+0

बहुत रोचक! –

4

संपादित करें मुझे लगता है कि अब मैं आपका प्रश्न समझता हूं, मैं अभी भी अपना मूल उत्तर नीचे रखूंगा।

y << ay.yield(a) के लिए उपनाम है, जो मूल रूप से sleep वापसी मूल्य के साथ है। प्रत्येक बार जब मूल्य next के साथ गणनाकर्ता से अनुरोध किया जाता है, तब तक निष्पादन जारी रहता है जब तक कि कोई अन्य मूल्य उत्पन्न न हो जाए।


ूगणकों तत्वों की एक सीमित संख्या की गणना करने की जरूरत नहीं है, इसलिए वे अनंत हैं। उदाहरण के लिए, fib.to_a कभी समाप्त नहीं होगा, क्योंकि यह तत्वों की अनंत संख्या के साथ सरणी बनाने का प्रयास करता है।

ऐसे में, एन्युमरेटर्स अनंत श्रृंखला जैसे प्राकृतिक संख्याओं, या आपके मामले में, फाइबोनैकी संख्याओं के प्रतिनिधित्व के रूप में महान हैं। गणनाकर्ता का उपयोगकर्ता यह तय कर सकता है कि उसे कितने मूल्यों की आवश्यकता है, इसलिए आपके उदाहरण में take(10) यदि आप करेंगे तो ब्रेक स्थिति निर्धारित करता है।

ब्रेक स्थिति स्वयं Enumerator#take के कार्यान्वयन में है। प्रदर्शन प्रयोजनों के लिए, हम अपने खुद के कार्यान्वयन my_take कहा जाता है कर सकते हैं:

class Enumerator 
    def my_take(n) 
    result = [] 
    n.times do 
     result << self.next 
    end 
    result 
    end 
end 

आप कहाँ निश्चित रूप से "मानसिक रूप से स्थानापन्न" अपने n.times अपने शास्त्रीय सी शैली for (i=0; i<n; i++) साथ पाश सकता है। आपकी ब्रेक हालत है। जैसे

fib.next 
#=> 1 
fib.next 
#=> 1 
fib.next 
#=> 2 
fib.next 
#=> 3 

जिसके अनुसार, आप निश्चित रूप से एक प्रगणक है कि मूल्यों की एक सीमित संख्या विश्लेषण करता है निर्माण कर सकते हैं,: self.next प्रगणक, जो आप भी वर्ग के बाहर का उपयोग कर सकते की अगली मूल्य प्राप्त करने की विधि है किसी दिए गए रेंज में प्राकृतिक संख्याएं, लेकिन यह मामला यहां नहीं है। फिर, जब आप next पर कॉल करने का प्रयास करते हैं तो गणनाकर्ता StopIteration त्रुटि उठाएगा, लेकिन सभी मानों को पहले ही समझाया गया है। उस स्थिति में, आपके पास दो ब्रेक स्थितियां हैं, इसलिए बोलने के लिए; जो पहले तोड़ता है वह जीत जाएगा। take वास्तव में त्रुटि से बचाव करके संभालता है, इसलिए निम्न कोड वास्तविक कार्यान्वयन के करीब थोड़ा सा है (हालांकि, take वास्तव में सी में लागू किया गया है)।

class Enumerator 
    def my_take(n) 
    result = [] 
    n.times do 
     result << self.next 
    end 
    result 
    rescue StopIteration 
    # enumerator stopped early 
    result 
    end 
end 
+0

कूल, लेकिन लूप को तोड़ने वाला कोई भी कथन कहां है? '<<'? –

+0

@LeszekAndrukanis मेरा संपादन देखें। गणक वास्तव में अनंत है, गणनाकर्ता में कोई ब्रेक स्थिति नहीं है। यह तय करने के लिए मूल्यों के उपभोक्ता पर निर्भर करता है कि वह कितने मूल्य चाहता है! –

+0

@ p11y मुझे लगता है कि ओपी जानना चाहता है कि कैसे रूबी प्रत्येक पुनरावृत्ति के बाद अनंत लूप को रोकने के लिए प्रबंधन करता है – Stefan

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