2012-04-17 12 views
14

में नेस्टेड सबराउटिन और स्कोपिंग मैं कुछ समय से पर्ल लिख रहा हूं और हमेशा नई चीजें खोज रहा हूं, और मैं बस कुछ दिलचस्प में भाग गया कि मेरे पास स्पष्टीकरण नहीं है, न ही इसे वेब पर मिला है।पर्ल

sub a { 
    sub b { 
    print "In B\n"; 
    } 
} 
b(); 

किस तरह मैं अपने दायरे के बाहर से b() कॉल कर सकते हैं और यह काम करता है?

मुझे यह करने के लिए एक बुरा अभ्यास पता है, और मैं इसे नहीं करता, मैं इन मामलों के लिए बंद और इस तरह के उपयोग का उपयोग करता हूं, लेकिन बस इसे देखा।

+0

आप केवल OOP के साथ –

+0

कुछ बंद होने से आपको मदद मिलेगी की तरह देखते हुए इस प्रकार की लागू कर सकता है;) यह एक ही आप के बारे में पूछ रहे हैं, लेकिन सबरूटीन्स का एक और अच्छा कार्यान्वयन नहीं है – gaussblurinc

+1

पर्ल v5.20 [शाब्दिक नामित सबरूटीन्स है। ] (http://www.effectiveperlprogramming.com/2015/01/named-lexical-subroutines/) –

उत्तर

15

सबराउटिन संकलन समय पर वैश्विक नामस्थान में संग्रहीत हैं। आपके उदाहरण में b();main::b(); के लिए छोटा हाथ है। फ़ंक्शन की दृश्यता को किसी दायरे में सीमित करने के लिए आपको एक चर के लिए अज्ञात सबराउटिन असाइन करने की आवश्यकता है।

नामित और अज्ञात सबराउटिन दोनों बंद हो सकते हैं, लेकिन चूंकि नामित सबराउटिन केवल तभी संकलित किए जाते हैं जब आप उन्हें घोंसला देते हैं तो वे बहुत से लोगों की अपेक्षा नहीं करते हैं।

use warnings; 
sub one { 
    my $var = shift; 
    sub two { 
     print "var: $var\n"; 
    } 
} 
one("test"); 
two(); 
one("fail"); 
two(); 
__END__ 
output: 
Variable "$var" will not stay shared at -e line 5. 
var: test 
var: test 

नेस्टिंग नामित सबरूटीन्स पर्ल में अनुमति दी है, लेकिन यह लगभग निश्चित रूप से एक संकेत है कि कोड को गलत तरीके से someting कर रही है।

+0

यह एक दिलचस्प उदाहरण है। आप कैसे समझाते हैं कि यह दूसरी बार 'var var' अपडेट नहीं करता है? उत्सुकता से, यदि आप लाइन 'एक ("टेस्ट") हटाते हैं, तो यह अपरिभाषित चर के बारे में शिकायत करता है, लेकिन फिर 'एक (" असफल ")' *** *** को 'var var' को अपडेट करने की अनुमति है। अपरिभाषित व्यवहार? – TLP

+0

मुझे विश्वास है कि मुझे [perlref] में जवाब मिला है (http://perldoc.perl.org/perlref.html#Function- टेम्पलेट्स) – TLP

+5

@ टीएलपी, 'उप दो {}' 'BEGIN {* दो = सब {}}' है, इसलिए यह संकलित होने पर मौजूद '$ var' पर कैप्चर करता है। 'मेरा' मूल रूप से एक 'नया' है जो स्कोप निकास पर होता है, इसलिए' $'' के पहले भाग के बाद '2'' 'var'' ''' 'var var' से अलग हो जाता है। – ikegami

2

सबराउटिन संकलन समय के दौरान परिभाषित किए जाते हैं, और दायरे से प्रभावित नहीं होते हैं। दूसरे शब्दों में, वे वास्तव में घोंसला नहीं कर सकते हैं। कम से कम जहां तक ​​उनके अपने दायरे का संबंध नहीं है। परिभाषित होने के बाद, वे स्रोत कोड से प्रभावी ढंग से हटा दिए जाते हैं।

+1

ठीक है, वे घोंसला जा सकते हैं, बस झुकाव से नहीं। –

+0

@briandfoy ऐसा लगता है कि मुझे पता था उससे कहीं अधिक है। [perlref] (http://perldoc.perl.org/perlref.html#Function- टेम्पलेट्स) में एक बहुत ही क्रिप्टिकल स्पष्टीकरण मिला। क्या यह व्यवहार जानबूझकर है? इसका क्या संभव उपयोग हो सकता है? – TLP

+0

@briandfoy - "मुझे लगता है 'घोंसला जा सकता है' आपका मतलब है 'भौतिक रूप से किसी अन्य उप कोड के अंदर रखा जा सकता है'; 'इस तरह के नेस्टेड प्लेसमेंट से प्रभावित अर्थशास्त्र हो सकता है' के विपरीत, सही? – DVK

5

निम्नलिखित प्रिंट 123

sub a { 
    $b = 123; 
} 

a(); 
print $b, "\n"; 

तो आप आश्चर्यचकित क्यों हैं कि निम्नलिखित भी करता है?

sub a { 
    sub b { return 123; } 
} 

a(); 
print b(), "\n"; 

कहीं $b या &b के लिए किसी भी अनुरोध शाब्दिक हो रहा है। वास्तव में, आप &b को लेक्सिकल (अभी तक) होने के लिए नहीं पूछ सकते हैं।

sub b { ... } 

मूल रूप से

BEGIN { *b = sub { ... }; } 

जहां *b के लिए प्रतीक तालिका प्रविष्टि है $b, @b, ..., और निश्चित रूप &b की। इसका मतलब है कि सबकुछ पैकेज से संबंधित है, और इस प्रकार पैकेज के भीतर कहीं से भी कहा जा सकता है, या कहीं भी अगर उनके पूर्ण योग्य नाम का उपयोग किया जाता है (MyPackage::b())।

3

पेर्ल में नेस्टेड सबराउटिन बनाने का "आधिकारिक" तरीका local कीवर्ड का उपयोग करना है। उदाहरण के लिए:

sub a { 
    local *b = sub { 
     return 123; 
    }; 
    return b(); # Works as expected 
} 

b(); # Error: "Undefined subroutine &main::b called at ..." 

perldoc पेज perlref इस उदाहरण है:

sub outer { 
    my $x = $_[0] + 35; 
    local *inner = sub { return $x * 19 }; 
    return $x + inner(); 
} 

"यह एक समारोह एक और कार्य करने के लिए स्थानीय बनाने की दिलचस्प प्रभाव पड़ता है, कुछ सामान्य रूप से पर्ल में समर्थित नहीं है।"