2012-11-28 8 views
13

मैं आर में समारोह on.exit है, जो बहुत अच्छा है के बारे में पता कर रहा हूँ। यह अभिव्यक्ति चलाता है जब कॉलिंग फ़ंक्शन निकलता है, या तो सामान्य रूप से या त्रुटि के परिणामस्वरूप।क्या .exit() पर अभिव्यक्ति चलाने का कोई तरीका है, लेकिन केवल सामान्य होने पर, त्रुटि पर नहीं?

मैं चाहता क्या अभिव्यक्ति केवल बुला सामान्य रूप से कार्य करता है, तो रिटर्न चलाने के लिए के लिए है, लेकिन एक गलती की स्थिति में नहीं। मेरे पास कई बिंदु हैं जहां फ़ंक्शन सामान्य रूप से वापस आ सकता है, और कई बिंदु जहां यह असफल हो सकता है। क्या इसे करने का कोई तरीका है?

myfunction = function() { 
    ... 
    on.exit(if (just exited normally without error) <something>) 
    ... 
    if (...) then return(point 1) 
    ... 
    if (...) then return(point 2) 
    ... 
    if (...) then return(point 3) 
    ... 
    return (point 4) 
} 

उत्तर

7

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

foo = function(thing){do something; return(thing)} 
myfunction = function() { 
    ... 
    if (...) then return(foo(point 1)) 
    ... 
    if (...) then return(foo(point 2)) 
    ... 
    if (...) then return(foo(point 3)) 
    ... 
    return (foo(point 4)) 
} 

या सिर्फ दो कथनों में प्रत्येक then खंड हैं। on.exit का उपयोग करते हुए स्थानों की एक संख्या में कुछ कोड लीवर डरावना कार्रवाई में एक दूरी समस्याओं के कारण और बच्चे डिज्कस्ट्रा रोना (पढ़ डिज्कस्ट्रा के "गोटो माना हानिकारक" कागज) बनाने के लिए जा रहा है।

+0

अच्छी सोच .. –

+0

+1 मैंने इसके बारे में सोचा नहीं था। मेरा 'कुछ करें' 'ग्लोबलएएनवी 'में ध्वज स्थापित कर रहा है (एक बहुत असामान्य स्थिति जो उस दृष्टिकोण को वारंट करती है, वादा करता है!)। हर बार एक ही कोड की पुनरावृत्ति के कारण प्रत्येक 'फिर' दो कथन को बदसूरत लग रहा था, इसलिए 'on.exit' मार्ग। लेकिन एक समारोह में 'कुछ करो' लपेटना साफ है! –

+0

euw! एकाधिक निकास पथ, बाहर निकलने वाले हैंडलर, और अब वैश्विक सेटिंग्स! डिज्कास्ट्रा उसकी कब्र में कताई होगी! – Spacedman

12

on.exit() के पूरे मुद्दे वास्तव में बाहर निकलने की स्थिति से बेपरवाह चलाने के लिए। इसलिए यह किसी भी त्रुटि संकेत की उपेक्षा करता है। यह tryCatch फ़ंक्शन के finally कथन के बराबर है।

आप केवल सामान्य बाहर निकलने पर कोड को चलाने के लिए चाहते हैं, बस इसे अपने कोड के अंत में डाल दिया। हाँ, आप इसे थोड़ा else बयानों का उपयोग करने और पुनर्गठन करने केवल 1 निकास बिंदु बनाने के द्वारा होगा, लेकिन है कि कुछ लोगों द्वारा अभ्यास कोडिंग अच्छा माना जाता है।

अपने उदाहरण का उपयोग करना, कि होगा:

myfunction = function() { 
    ... 
    if (...) then out <- point 1 
    ... 
    else if (...) then out <- point 2 
    ... 
    else if (...) then out <- point 3 
    ... 
    else out <- point 4 

    WhateverNeedsToRunBeforeReturning 

    return(out) 
} 

या इस विचार local() का उपयोग करने का एक अच्छा कार्यान्वयन के लिए answer of Charles देखते हैं।

आप on.exit() के प्रयोग पर जोर देते हैं, तो आप इस तरह कुछ करने के लिए ट्रैस बैक तंत्र की कार्यप्रणाली पर जुआ कर सकते हैं:

test <- function(x){ 
    x + 12 
}        

myFun <- function(y){ 
    on.exit({ 

     err <- if(exists(".Traceback")){ 
      nt <- length(.Traceback)   
      .Traceback[[nt]] == sys.calls()[[1]] 
     } else {FALSE} 

     if(!err) print("test") 
    }) 
    test(y) 
} 

.Traceback एक त्रुटि में जिसके परिणामस्वरूप पिछले कॉल स्टैक में शामिल है। आपको यह जांचना होगा कि उस स्टैक में शीर्ष कॉल वर्तमान कॉल के बराबर है, और उस स्थिति में आपकी कॉल ने आखिरी त्रुटि को फेंक दिया है। तो उस स्थिति के आधार पर आप खुद को एक समाधान को हैक करने का प्रयास कर सकते हैं जिसे मैं कभी भी उपयोग नहीं करता।

+0

+1 बहुत धन्यवाद। मुझे पता है कि आपका क्या मतलब है और पूरी तरह से सहमत हैं। लेकिन मेरे पास विशेष स्थिति में, कोड पुनर्गठन करना मुश्किल होगा। मैं 'अगर (बिना त्रुटि के सामान्य रूप से बाहर निकला)' भाग करने का एक तरीका उम्मीद कर रहा था; उदाहरण के लिए, क्या 'आखिरी आतंक' या कुछ है, जैसा कि 'last.value'' है? –

+0

@MatthewDowle वहाँ है, और यह 'geterrmessage()' द्वारा प्राप्त किया जाता है। लेकिन अगर आपने कोड चलाया है जो आपके फ़ंक्शन को चलाने से पहले एक त्रुटि देता है, तो 'geterrmessage()' उस त्रुटि को वापस कर देगा। यही कारण है कि आपको 'sys.calls() 'और '.Traceback' का उपयोग करके कॉल स्टैक को अपने दूसरे उदाहरण में देखना होगा। यह 'अगर (सामान्य रूप से बाहर निकला) 'आप पूछते हैं। मुझे नहीं पता कि समाधान कितना स्थिर है, इसलिए मैं इस पर शर्त नहीं लगाऊंगा। –

+0

बहुत बढ़िया, धन्यवाद! पहले 'ट्रेसबैक' के बारे में नहीं पता था। मैं उसमें देख लूंगा ... –

6

बिट @Joris 'जवाब पर मेरी टिप्पणी का अधिक पठनीय संस्करण:

f = function() { 
    ret = local({ 
    myvar = 42 
    if (runif(1) < 0.5) 
     return(2) 
    stop('oh noes') 
    }, environment()) 
    # code to run on success... 
    print(sprintf('myvar is %d', myvar)) 
    ret 
} 
+0

+1 यह अनिवार्य रूप से एक और (अच्छा) तरीका है जो मैंने पहले कहा था: उस कोड को चलाएं जिसे आप अपने फ़ंक्शन के अंत में चलाने के लिए चाहते हैं। साथ ही, बस बताएं कि आप क्या करते हैं, इसलिए लोगों को मेरे उत्तर के तहत टिप्पणियों के भार में खोदने की ज़रूरत नहीं है। –

+0

+1 भी। जैसा कि आपने दिखाया है, मैं उस स्थानीय के साथ अपने मौजूदा फ़ंक्शन बॉडी को बस लपेट सकता हूं। उस बारे में भी नहीं सोचा था। धन्यवाद! प्रयोग करेंगे ... –

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

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