2009-03-21 7 views
5

में स्कोप परिवर्तन पर कोड डालें, मुझे अक्सर वर्तमान स्कोप छोड़ने के लिए कोड शेड्यूल करने में सक्षम होने के लिए उपयोगी लगता है। टीसीएल में मेरे पिछले जीवन में, एक दोस्त ने एक फ़ंक्शन बनाया जिसे हम डिफर कहते हैं।पर्ल

यह कोड सक्षम करता है जैसे: सेट fp [open "x"] डिफर ("$ $ fp");

जो वर्तमान दायरे से बाहर निकलने पर लागू किया गया था। मुख्य लाभ यह है कि यह हमेशा कोई फर्क नहीं पड़ता कि मैं कैसे/कहाँ गुंजाइश छोड़ देता हूं।

इसलिए मैंने पर्ल में कुछ ऐसा ही लागू किया लेकिन ऐसा लगता है कि वहां एक आसान तरीका होगा। टिप्पणियाँ आलोचकों का स्वागत है।

तरह से मैं पर्ल में यह किया:

  • एक वैश्विक, बंधे चर जो निष्पादित करने के लिए बाद के चरणों की एक सरणी रखती पैदा करते हैं।
  • जब भी मैं बाहर निकलने के लिए एक एफएन शेड्यूल करना चाहता हूं, तो मैं सरणी को बदलने के लिए स्थानीय का उपयोग करता हूं। जब मैं वर्तमान दायरा छोड़ देता हूं, पर्ल वैश्विक को पिछले मान में बदल देता है क्योंकि वैश्विक बंधे हैं, मुझे पता है कि यह मान परिवर्तन कब होता है और सूची में उप-सब्सक्राइब कर सकता है।

वास्तविक कोड नीचे है।

क्या ऐसा करने का कोई बेहतर तरीका है? ऐसा लगता है कि यह एक सामान्य रूप से आवश्यक क्षमता होगी।

use strict; 

package tiescalar; 

sub TIESCALAR { 
    my $class = shift; 

    my $self = {}; 
    bless $self, $class; 
    return $self; 
} 

sub FETCH { 
    my $self = shift; 
    return $self->{VAL}; 
} 

sub STORE { 
    my $self = shift; 
    my $value = shift; 

    if (defined($self->{VAL}) && defined($value)) { 
    foreach my $s (@{$self->{VAL}}) { &$s; } 
    } 
    $self->{VAL} = $value; 
} 

1; 

package main; 

our $h; 
tie($h, 'tiescalar'); 
$h = []; 
printf "1\n"; 
printf "2\n"; 

sub main { 
    printf "3\n"; 
    local $h = [sub{printf "9\n"}]; 
    push(@$h, sub {printf "10\n";}); 
    printf "4\n"; 
    { 
    local $h = [sub {printf "8\n"; }]; 
    mysub(); 
    printf "7\n"; 
    return; 
    } 
} 

sub mysub { 
    local $h = [sub {printf "6\n"; }]; 
    print "5\n"; 
} 

main(); 

printf "11\n"; 

उत्तर

4

खैर , यदि आप लेक्सिकल फ़ाइल हैंडल का उपयोग करते हैं (पुराने स्टाइल नर्डवर्ड फाइलहेन्डल्स के विपरीत) तो आपका विशिष्ट मामला पहले से ही संभाला जा चुका है।

#!/usr/bin/perl 

use strict; 
use warnings; 

for my $i (1 .. 5) { 
    my $defer = Defer::Sub->new(sub { print "end\n" }); 
    print "start\n$i\n"; 
} 

package Defer::Sub; 

use Carp; 

sub new { 
    my $class = shift; 
    croak "$class requires a function to call\n" unless @_; 
    my $self = { 
     func => shift, 
    }; 
    return bless $self, $class; 
} 

sub DESTROY { 
    my $self = shift; 
    $self->{func}(); 
} 

अनुमानित समय: मैं पसंद ब्रायन के नाम बेहतर, स्कोप :: OnExit एक बहुत अधिक है अन्य मामलों के लिए, आप हमेशा जब यह दायरे से बाहर चला जाता है एक वस्तु शून्य संदर्भ के लिए जाने की गारंटी की विधि को नष्ट कर इस्तेमाल कर सकते हैं वर्णनात्मक नाम।

1

मुझे लगता है कि आप Scope::Guard की तरह कुछ चाहते हैं, लेकिन ऐसा नहीं धकेल दिया जा सकता है। हममम।

धन्यवाद।

4

इसके लिए टाई का उपयोग करने के बजाय, मुझे लगता है कि मैं सिर्फ एक वस्तु बनाउंगा। आप local से भी इस तरह से बच सकते हैं।

{ 
my $defer = Scope::OnExit->new(@subs); 
$defer->push($other_sub); # and pop, shift, etc 

... 
} 

जब परिवर्तक गुंजाइश से बाहर हो जाता है, तो आपको DESTROY विधि में चीजों को करने का मौका मिलता है।

इसके अलावा, उदाहरण आप पोस्ट में, आप जांच करने के लिए है कि मूल्यों आप स्टोर कोड संदर्भ हैं की जरूरत है, और यह शायद एक अच्छा विचार है यह देखना होगा कि VAL मूल्य एक सरणी संदर्भ है:

 
sub TIESCALAR { bless { VAL => [] }, $_[0] } 

sub STORE { 
    my($self, $value) = @_; 

    carp "Can only store array references!" unless ref $value eq ref []; 

    foreach { @$value } { 
     carp "There should only be code refs in the array" 
      unless ref $_ eq ref sub {} 
     } 

    foreach (@{ $self->{VAL}}) { $_->() } 


    $self->{VAL} = $value; 
    } 
3

आप बाहर की कोशिश करना चाहते हो सकता है B::Hooks::EndOfScope

मैं विश्वास है कि यह काम करता है:

use B::Hooks::EndOfScope; 

    sub foo { 
     on_scope_end { 
       $codehere; 
     }; 
     $morecode 
     return 1; # scope end code executes. 
    } 

    foo(); 
+0

यह एक अच्छा विचार है, लेकिन मैं एक बेहतर संस्करण बनाना चाहता हूं उस। कार्यान्वयन थोड़ा बोझिल IMHO है। –

1
तुच्छता

,

sub OnLeavingScope::DESTROY { ${$_[0]}->() } 

की तरह इस्तेमाल किया:

{ 
    ... 
    my $onleavingscope = bless \sub { ... }, 'OnLeavingScope'; 
    my $onleavingscope2 = bless \\&whatever, 'OnLeavingScope'; 
    ... 
} 

(अतिरिक्त स्तर हवल का एक उप-संदर्भ के संदर्भ के संदर्भ में केवल एक अनुकूलन के आसपास काम करने के लिए जरूरी है (यह तर्कसंगत रूप से एक बग है) गैर-बंद अज्ञात उप का उपयोग करते समय।