2010-09-15 13 views
30

अधिकांश अन्य भाषाओं में, पकड़ और फेंक बयान रूबी में शुरू, बचाव, और बयान उठाने के लिए करते हैं। मैं जानता हूँ कि आप इन दो बयानों के साथ ऐसा कर सकते हैं:रूबी में कैच और फेंक क्या है?

catch :done do 
    puts "I'm done." 
end 

और

if some_condition 
    throw :done 
end 

लेकिन क्या के लिए यह उपयोगी है? क्या कोई मुझे रूबी में कैच और फेंक स्टेटमेंट का उपयोग करने का उदाहरण दे सकता है?

+1

संभावित डुप्लिकेट: http://stackoverflow.com/questions/51021/what-is-the-differance-between-raising-exceptions-vs-throwing-exceptions-in-ruby – Shadwell

उत्तर

32

आप इसे नेस्टेड लूप से बाहर निकलने के लिए उपयोग कर सकते हैं।

INFINITY = 1.0/0.0 
catch (:done) do 
    1.upto(INFINITY) do |i| 
    1.upto(INFINITY) do |j| 
     if some_condition 
     throw :done 
     end 
    end 
    end 
end 

यदि आपने उपरोक्त ब्रेक स्टेटमेंट का उपयोग किया था, तो यह आंतरिक लूप से टूट जाएगा। लेकिन अगर आप नेस्टेड लूप से बाहर निकलना चाहते हैं, तो यह पकड़/फेंक वास्तव में सहायक होगा। मैंने यूलर समस्याओं में से एक को हल करने के लिए here का उपयोग किया है।

21

मैं थोड़ी देर के लिए एक अच्छा उदाहरण ढूंढ रहा हूं, जब तक कि मैं सिनात्रा से मुलाकात नहीं करता। आईएमएचओ, सिनात्रा catch के लिए एक बहुत ही रोचक उदाहरण उपयोग का खुलासा करता है।

सिनात्रा में आप किसी भी समय halt का उपयोग कर सकते हैं।

halt 

जब रोकने तुम भी स्थिति का उल्लेख कर सकते हैं ...

halt 410 

या शरीर ...

halt 'this will be the body' 

या दोनों ...

halt 401, 'go away!' 

रोक विधि implemented using throw है।

def halt(*response) 
    response = response.first if response.length == 1 
    throw :halt, response 
end 

और caught byinvoke विधि।

सिनात्रा में :halt के कई उपयोग हैं। आप अधिक उदाहरणों के लिए स्रोत कोड पढ़ सकते हैं।

+1

बस सोच रहा है, यह बेहतर कैसे है अपवादों का उपयोग करने से? – jsz

+2

नियंत्रण प्रवाह के रूप में अपवाद जैसी प्रणाली का उपयोग करने के लिए यह एक और अधिक सुरुचिपूर्ण तरीका है। –

+2

@jsz एक के लिए, यह बहुत तेज़ है-स्टैक फ्रेम को "फेंकने वाले प्रतीक" के साथ नहीं ले जाना पड़ता है, और कोई ऑब्जेक्ट नहीं बनाया जाता है। हल्के nonlinear प्रवाह नियंत्रण। – mezis

1

जब पुनरावर्ती एल्गोरिदम कि पुनरावर्ती कार्यों का उपयोग कर नेस्टेड डेटा संरचनाओं पर कार्रवाई लेखन, आप कैसे आप एक break या जल्दी return जब लेखन पुनरावृत्ति एल्गोरिदम कि for छोरों का उपयोग कर फ्लैट डेटा पर कार्रवाई का प्रयोग करेंगे करने के लिए इसी तरह throw उपयोग कर सकते हैं।

उदाहरण के लिए, मान लीजिए आप एक समारोह है कि सच वापस आ जाएगी लिखने के लिए धनात्मक पूर्णांक की एक सूची है कि और आप (किसी कारण के लिए) चाहते हैं, तो निम्न स्थितियों में से किसी से मुलाकात कर रहे:

  • का योग सूची के सभी तत्वों 100 से अधिक
  • सूची में कुछ तत्व अगर करने के लिए 5

की भी है कि आप हमेशा सूची पर एक एकल, शॉर्ट-सर्किट पास में यह जाँच करने के लिए चाहते हैं मान लीजिए बराबर है, reduce सी करने के बजाय सभी को योग प्राप्त करने के लिए और अलग any? कॉल प्राप्त करने के लिए कॉल करें।

आप शायद इस तरह एक सा कुछ कोड लिखने चाहते हैं (वास्तव में, आप शायद कोड इस तरह कुछ भाषा में कुछ बिंदु पर अपने जीवन में लिखा है):

def test(list) 
    sum = 0 
    for i in list 
    sum += i 
    if i == 5 || sum > 100 
     return true 
    end 
    end 
    return false 
end 

सबसे अधिक भाषाओं में, वहाँ कोई है रिकर्सिव फ़ंक्शन का उपयोग करने वाले रिकर्सिव एल्गोरिदम से बाहर निकलने के लिए साफ समकक्ष। रूबी में, हालांकि, वहाँ है! मान लीजिए कि, सूची रखने के बजाय और यह जांचना चाहते हैं कि उसके तत्वों में पांच या योग 100 से अधिक हैं, तो आपके पास पेड़ है और यह जांचना है कि में पांच या योग 100 से अधिक हो, जबकि कम - जैसे ही आप जवाब जानते हैं, उतनी जल्दी लौट रहे हैं।

आप इस तरह throw/catch साथ सुंदर ढंग से ऐसा कर सकते हैं,:

def _test_recurse(sum_so_far, node) 
    if node.is_a? InternalNode 
    for child_node in node.children 
     sum_so_far = _test_recurse(sum_so_far, child_node) 
    end 
    return sum_so_far 
    else # node.is_a? Leaf 
    sum_so_far += node.value 
    if node.value == 5 
     throw :passes_test 
    elsif sum_so_far > 100 
     throw :passes_test 
    else 
     return sum_so_far 
    end 
    end 
end 

def test(tree)    
    catch (:passes_test) do 
    _test_recurse(0, tree) 
    return false 
    end 
    return true 
end 

यहाँ throw :passes_test एक break की तरह एक सा कार्य करता है; यह आपको बाहरी कॉल _test कॉल के नीचे अपने पूरे कॉल स्टैक से बाहर निकलने देता है। अन्य भाषाओं में, आप इस उद्देश्य के लिए अपवादों का दुरुपयोग करके या रिकर्सिंग फ़ंक्शन को रिकर्सिंग रोकने के लिए कुछ रिटर्न कोड का उपयोग करके ऐसा कर सकते हैं, लेकिन यह अधिक प्रत्यक्ष और सरल है।

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