2012-11-29 25 views
6

आज त्रुटि समस्या को पकड़ने के लिए, मैंने erlang's त्रुटि और त्रुटि हैंडलिंग दस्तावेज़ पढ़े हैं।Erlang में फेंक/1 बनाम निकास/1 बनाम त्रुटि/1 का उपयोग कब करें?

उत्पन्न त्रुटि प्रकार के लिए, 2 प्रकार के वर्ग हैं, एक exit है और दूसरा throw है। मेरे स्रोत कोड को grepping करने के बाद, throw and exit अभिव्यक्ति पहले ही बड़े पैमाने पर हो चुकी है।

दोनों समान हैं, और लगता है कि केवल मैच मिलान अभिव्यक्ति अलग है।

([email protected])30> catch throw ({aaa}). 
{aaa} 
([email protected])31> catch exit ({aaa}). 
{'EXIT',{aaa}} 
([email protected])32> catch gen_server:call(aaa,{aaa}). 
{'EXIT',{noproc,{gen_server,call,[aaa,{aaa}]}}} 

क्या आप मुझे बता जब फेंक उपयोग करने के लिए किया जा सका और जब बाहर निकलने के उपयोग करने के लिए?

उत्तर

12

वर्ग है जो एक try ... catch साथ पकड़ा जा सकता है।

  • throwthrow/1 का उपयोग कर उत्पन्न होता है और गैर स्थानीय रिटर्न लिए इस्तेमाल किया जा करने का इरादा है और जब तक यह पकड़ा नहीं है एक त्रुटि उत्पन्न नहीं करता है (जब आप एक nocatch त्रुटि मिलती है)।

  • error उत्पन्न होता है जब सिस्टम किसी त्रुटि का पता लगाता है। आप error/1 का उपयोग करके स्पष्ट रूप से एक त्रुटि उत्पन्न कर सकते हैं। सिस्टम में उत्पन्न त्रुटि मान में एक स्टैकट्रैक भी शामिल है, उदाहरण के लिए {badarg,[...]}

  • exitexit/1 का उपयोग करके उत्पन्न किया गया है और यह संकेत है कि यह प्रक्रिया मरनी है।

error/1 और exit/1 के बीच अंतर यह है कि महान नहीं है, यह इरादा जो त्रुटियों के द्वारा उत्पन्न स्टैकट्रेस को बढ़ाता है के बारे में अधिक।

उनके बीच के अंतर वास्तव में अधिक ध्यान देने योग्य जब catch ... कर रही है: जब throw/1 प्रयोग किया जाता है तो catch बस फेंक दिया मान देता है, के रूप में एक गैर-स्थानीय वापसी से उम्मीद है; जब error/1 का उपयोग किया जाता है तो catch{'EXIT',Reason} देता है जहां Reason में स्टैकट्रैक होता है; जबकि exit/1catch से {'EXIT',Reason} भी लौटाता है लेकिन Reason में केवल वास्तविक निकास कारण होता है। try ... catch ऐसा लगता है कि यह समान है, लेकिन वे बहुत अलग हैं।

+0

आपकी मदद के लिए बहुत बहुत धन्यवाद। यह अब और अधिक स्पष्ट है। –

+0

@ चेन्यू - मेरी मैला स्पष्टीकरण के लिए क्षमा चाहते हैं। rvirding - इसे साफ़ करने के लिए धन्यवाद। मुझे या तो मेरा जवाब ठीक/हटाने दें - कम भ्रम बेहतर! – Faiz

6

[अपडेट]

मैं फेंक और त्रुटि के बीच महत्वपूर्ण अंतर पर भुला, बाहर रॉबर्ट Virding से इशारा किया। यह संपादन सिर्फ रिकॉर्ड के लिए है!

फेंकerror जहां एक अन्य भाषाओं में throw का प्रयोग करेंगे प्रयोग की जाने वाली है। आपके कोड द्वारा चल रही प्रक्रिया में एक त्रुटि का पता चला है, जो error/1 के साथ अपवाद को इंगित करता है। एक ही प्रक्रिया इसे पकड़ती है (संभवतः ढेर में ऊंची होती है), और उसी प्रक्रिया में त्रुटि को संभाला जाना है। error हमेशा इसके साथ एक stacktrace लाता है।

throw का उपयोग किसी त्रुटि को सिग्नल न करने के लिए किया जाना है, लेकिन केवल गहरा घोंसला वाले फ़ंक्शन से मूल्य वापस करने के लिए। चूंकि यह स्टैक को खोलता है, throw को कॉल करने वाले स्थान पर फेंक दिया गया मूल्य देता है। error के मामले में, हम फेंकने वाली चीजें पकड़ रहे हैं, केवल जो फेंक दिया गया था वह त्रुटि नहीं थी बल्कि सिर्फ एक मूल्य ढेर को पार कर गया था। यही कारण है कि फेंक इसके साथ एक ढेर नहीं लाता है।

एक काल्पनिक उदाहरण के रूप में, अगर हम सूचियों के लिए एक exists समारोह, (क्या list:any करता है के समान) को लागू करने और एक व्यायाम बिना खुद recursing कर रही है, और सिर्फ list:foreach का उपयोग किए बिना के रूप में, तो throw इस्तेमाल किया जा सकता चाहता था यहाँ:

exists(P, List) -> 
    F = fun(X) -> 
    case P(X) of 
     true -> throw(true); 
     Whatever -> Whatever 
    end 
    end, 
    try lists:foreach(F, List) of 
    ok -> false 
    catch 
    true -> true 
    end. 

एक मूल्य फेंक दिया लेकिन नहीं करते पकड़ा एक error के रूप में व्यवहार किया जाता है: एक nocatch अपवाद उत्पन्न हो जाएगा।

EXIT को प्रक्रिया द्वारा संकेतित किया जाना चाहिए जब यह 'छोड़ देता है'पैरेंट प्रक्रिया EXIT को संभालती है, जबकि बाल प्रक्रिया बस मर जाती है। यह Erlang चलो-यह-दुर्घटना दर्शन है।

तो exit/1 का EXIT उसी प्रक्रिया में पकड़ा नहीं जाना चाहिए, लेकिन माता-पिता को छोड़ दिया गया है। error/1 की त्रुटियां प्रक्रिया के लिए स्थानीय हैं - यानी, क्या होता है और यह प्रक्रिया को प्रक्रिया द्वारा पर कैसे संभाला जाता है; throw/1 स्टैक में नियंत्रण प्रवाह के लिए उपयोग किया जाता है।

[अद्यतन]

  1. इस ट्यूटोरियल यह अच्छी तरह से बताते हैं: http://learnyousomeerlang.com/errors-and-exceptions
  2. नोट वहाँ भी एक exit/2 है - एक Pid एक प्रक्रिया का के साथ बुलाया बाहर निकलने के लिए भेजने के लिए। exit/1 मूल प्रक्रिया का तात्पर्य है। throw, error और exit:
+0

आपकी जानकारी के लिए बहुत बहुत धन्यवाद। –

+0

@ चेन्यू अगर आप अध्याय पढ़ते हैं तो आप देखेंगे कि यहां स्पष्टीकरण गलत है। गैर-स्थानीय रिटर्न करने के लिए आप 'फेंक/1' का उपयोग करते हैं, ** कोई त्रुटि फेंकने के लिए ** नहीं, आप त्रुटि को सिग्नल करने के लिए' त्रुटि/1' का उपयोग करते हैं और आप यह दिखाने के लिए बाहर निकलें/1' 'प्रक्रिया है कि प्रक्रिया है मर जाते हैं। ** 3 ** प्रकार के वर्ग हैं: 'फेंक', 'त्रुटि' और 'बाहर निकलें' – rvirding

+0

@ रिवॉर्डिंग आशा है कि मैंने इसके साथ संशोधन किया है। प्रतिक्रिया की सराहना की! – Faiz

0

मैं Erlang के लिए नया हूँ, लेकिन यहाँ है कि वे क्या, के लिए इस्तेमाल कर रहे हैं, मैं कैसे लगता है क्या इन बातों को, कर रहे हैं अपने मतभेदों के बारे आदि .:

throw: एक शर्त है कि स्थानीय स्तर पर संभाला जाना चाहिए (यानी वर्तमान प्रक्रिया के भीतर)। जैसे कॉलर संग्रह में तत्व की तलाश में है, लेकिन यह नहीं जानता कि संग्रह में वास्तव में ऐसा तत्व है या नहीं; तो, कैलिली फेंक सकता है अगर ऐसा तत्व मौजूद नहीं है, और कॉलर try[/of]/catch का उपयोग करके अनुपस्थिति का पता लगाता है। यदि कॉलर ऐसा करने की उपेक्षा करता है, तो यह nocatcherror (नीचे समझाया गया) में बदल जाता है।

exit: वर्तमान प्रक्रिया पूरी की जाती है। जैसे यह बस समाप्त हो गया है (उस स्थिति में, आप normal पास करेंगे, जिसे मूल फ़ंक्शन रिटर्निंग के समान माना जाता है), या उसका ऑपरेशन रद्द कर दिया गया था (उदा। यह सामान्य रूप से अनिश्चित काल तक लूप करता है लेकिन उसे अभी shut_down संदेश प्राप्त हुआ है)।

error: प्रक्रिया कुछ किया है और/या एक राज्य है कि प्रोग्रामर नहीं (उदाहरण के लिए 1/0) को ध्यान में रखना था पर पहुंच गया, का मानना ​​है कि असंभव है (उदाहरण के लिए case ... of एक मूल्य है कि किसी भी मामले से मेल नहीं खाता का सामना करना पड़ता है), या कुछ पूर्व शर्त नहीं मिली है (जैसे इनपुट nonempty है)। इस मामले में, स्थानीय वसूली समझ में नहीं आता है। इसलिए, न तो throw और न ही exit उपयुक्त है। चूंकि यह अप्रत्याशित है, इसलिए एक स्टैक ट्रेस कारण का हिस्सा है।

आप देख सकते हैं, उपरोक्त सूची बढ़ते क्रम में है:

throw समझदार की स्थिति है कि फोन करने वाले को संभालने के लिए आशा की जाती है के लिए है। अर्थात। हैंडलिंग वर्तमान प्रक्रिया के भीतर होती है।

exit भी सचेत है, लेकिन प्रक्रिया पूरी होने के कारण वर्तमान प्रक्रिया को समाप्त करना चाहिए।

error पागल है। कुछ ऐसा हुआ जो उचित रूप से (आमतौर पर एक बग?) से पुनर्प्राप्त नहीं किया जा सकता है, और स्थानीय रिकवरी उचित नहीं होगी।


बनाम अन्य भाषाओं:

throw रास्ता के अनुरूप है जांचे हुए अपवादों जावा में किया जाता है। जबकि, error अनचेक अपवादों के समान तरीके से उपयोग किया जाता है। चेक अपवाद अपवाद हैं जिन्हें आप कॉलर को संभालना चाहते हैं। जावा के लिए आपको या तो try/catch में कॉल लपेटने की आवश्यकता है या यह घोषणा करें कि आपकी विधि throws ऐसे अपवाद हैं। हालांकि, अनचेक अपवाद आम तौर पर बाहरीतम कॉलर को प्रचारित करते हैं।

exit जावा, सी ++, अजगर, जावास्क्रिप्ट, रूबी, आदि exit अस्पष्ट एक uber- return की तरह की तरह अधिक "पारंपरिक" भाषाओं में एक अच्छा अनुरूप नहीं है: अंत में लौटने के बजाय, आप से लौट सकते हैं एक समारोह के बीच, सिवाय इसके कि आप वर्तमान कार्य से वापस नहीं आते हैं, आप उन सभी से वापस आते हैं।


exit उदाहरण

serve_good_times() -> 
    receive 
    {top_of_the_mornin, Sender} -> 
     Sender ! and_the_rest_of_the_day_to_yourself; 
    {you_suck, Sender} -> 
     Sender ! take_a_chill_pill; 
    % More cases... 

    shut_down -> 
     exit(normal) 
    end, 
    serve_good_times() 
end 

serve_good_times के बाद से कॉल ही लगभग के बाद सभी संदेशों, प्रोग्रामर का फैसला किया है कि हम उस कॉल को दोहराने के लिए हर मामले प्राप्त में नहीं करना चाहती। इसलिए, उसने को प्राप्त करने के बाद कॉल किया है। लेकिन फिर, क्या होगा अगर serve_good_times खुद को कॉल करना बंद करने का फैसला करता है? यह वह जगह है जहां exit बचाव के लिए आता है। normal से exit पास करने की प्रक्रिया को समाप्त करने का कारण बनता है जैसे अंतिम फ़ंक्शन कॉल वापस आ गया है।

इस प्रकार, आमतौर पर exit को सामान्य प्रयोजन लाइब्रेरी में lists पर कॉल करने के लिए अनुचित है। यह लाइब्रेरी का कोई भी व्यवसाय नहीं है कि प्रक्रिया समाप्त होनी चाहिए; यह आवेदन कोड द्वारा तय किया जाना चाहिए।


असामान्य exit के बारे में क्या?

यह मायने रखती है, तो किसी अन्य प्रक्रिया ("दूरस्थ" प्रक्रिया) "स्थानीय" प्रक्रिया है कि exit कॉल (और process_flag(trap_exit, true) आमंत्रित नहीं किया गया) से जुड़ा हुआ है: बस लौटने पिछले समारोह की तरह, exit(normal) दूरस्थ प्रक्रिया का कारण नहीं है बाहर निकलने के लिए । लेकिन यदि स्थानीय प्रक्रिया exit(herp_derp) कॉल करती है, तो दूरस्थ प्रक्रिया Reason=herp_derp से भी निकलती है। बेशक, अगर रिमोट प्रक्रिया अभी तक और अधिक प्रक्रियाओं से जुड़ा हुआ है, तो उन्हें Reason=herp_derp के साथ एक्जिट सिग्नल भी मिलता है। इसलिए, गैर-normal परिणाम श्रृंखला प्रतिक्रिया में निकलता है।

की कार्रवाई में इस पर एक नज़र डालें:

1> self(). 
<0.32.0> 
2> spawn_link(fun() -> exit(normal) end). 
<0.35.0> 
3> self(). 
<0.32.0> 
4> 
4> 
4> spawn_link(fun() -> exit(abnormal) end). 
** exception exit: abnormal 
5> self(). 
<0.39.0> 
6> 

पहली प्रक्रिया है कि हम पैदा की बाहर निकलने के लिए खोल का कारण नहीं (हम बता सकते हैं, क्योंकि self से पहले और spawn_link के बाद ही पीआईडी ​​लौटे)। लेकिन दूसरी प्रक्रिया ने खोल को बाहर निकालने का कारण बनाया (और सिस्टम ने शैल प्रक्रिया को एक नए से बदल दिया)।

बेशक

, दूरस्थ प्रक्रिया process_flag(trap_exit, true) का उपयोग करता है तो यह सिर्फ एक संदेश हो जाता है, स्थानीय प्रक्रिया से गुजरता है कि क्या normal या exit कुछ और की परवाह किए बिना। इस ध्वज को सेट करने से चेन प्रतिक्रिया बंद हो जाती है।

6> process_flag(trap_exit, true). 
false 
7> spawn_link(fun() -> exit(normal) end). 
<0.43.0> 
8> self(). 
<0.39.0> 
9> flush(). 
Shell got {'EXIT',<0.43.0>,normal} 
ok 
10>           
10> 
10> spawn_link(fun() -> exit(abnormal) end). 
<0.47.0> 
11> self(). 
<0.39.0> 
12> flush(). 
Shell got {'EXIT',<0.47.0>,abnormal} 

याद मैंने कहा कि कि exit(normal) लौटने मूल कार्य की तरह व्यवहार किया जाता है:

13> spawn_link(fun() -> ok end). 
<0.51.0> 
14> flush(). 
Shell got {'EXIT',<0.51.0>,normal} 
ok 
15> self(). 
<0.39.0> 

क्या तुम जानते हो: एक ही बात है जब exit(normal) बुलाया गया था के रूप में हुआ। आश्चर्यजनक!

+0

बीटीडब्ल्यू, बाहर निकलें (स्वयं(), wat) बाहर निकलने के बराबर नहीं है (wat)। दोनों अलग-अलग व्यवहार करते हैं जब process_flag (trap_exit, true) उपयोग में है (वर्तमान धागे से): पूर्व परिणाम 'EXIT' संदेश में होते हैं; जबकि, उत्तरार्द्ध वास्तव में वहां और फिर बाहर निकलता है। – allyourcode

+0

यदि आप बाहर निकलें (नहीं, स्वयं, कारण) और NotSelf trap_exit का उपयोग नहीं कर रहा है, तो यह बाहर निकलने के बजाय एक संदेश प्राप्त करता है, जैसे रिमोट (स्वयं के परिप्रेक्ष्य से) बाहर निकला था। मेरे लिए, यह वास्तव में अनजान है; मैंने सोचा था कि trap_exit केवल रिमोट प्रक्रियाओं से बाहर निकलने से संबंधित है, लेकिन यह स्वयं() से बाहर निकलने पर भी बाहर निकलने पर बाहर निकलने पर स्वयं पर लागू होता है! मेरा मस्तिष्क (और मेरी भावनाएं) अभी दर्द होता है ... – allyourcode

+0

एक और चीज जिसे मुझे बाहर निकलने के लिए {'EXIT', पिड, कारण} संदेशों के बारे में पता नहीं था: पिड वह प्रक्रिया है जो बाहर निकलने/2 कहती है , निकास/2 के पहले तर्क द्वारा नामित प्रक्रिया नहीं। पागल ... – allyourcode

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