2012-06-05 10 views
5

एक चर के एक चर को देखते हुए एक पैकेज के नाम का प्रतिनिधित्व करता है, मैं पैकेज के विशिष्ट सबराउटिन को कैसे कॉल करूं?पर्ल में पैकेज नाम दिए गए, आप पैकेज से सबराउटिन कैसे कॉल करते हैं?

यहाँ निकटतम बात मैं पता लगा है है:

package MyPackage; 

sub echo { 
    print shift; 
} 

my $package_name = 'MyPackage'; 
$package_name->echo('Hello World'); 

1; 

सबरूटीन एक वर्ग पद्धति के रूप में कहा जाता है इस कोड के साथ समस्या; पैकेज नाम पहले तर्क के रूप में पारित किया गया है। मैं पैकेज नाम से subroutine को विशेष रूप से पारित किए जाने वाले विशेष पहले तर्क के बिना आह्वान करना चाहता हूं।

+1

यदि आप एक आक्रमणकर्ता को पास नहीं करना चाहते हैं, तो आप जो चाहते हैं वह * विधि * को कॉल नहीं करना है। – hobbs

+0

@ हॉब्स: धन्यवाद। मैंने प्रश्न को और सही शब्दावली का उपयोग करने के लिए अद्यतन किया है। "नो सख्त 'रेफरी के लिए – Sam

उत्तर

4

पर्ल विधि कॉल बस नियमित सबरूटीन्स, जो पहले मूल्य के रूप में invocant प्राप्त कर रहे हैं।

use strict; 
use warnings; 
use 5.10.1; 

{ 
    package MyPackage; 
    sub new{ bless {}, shift } # overly simplistic constructor (DO NOT REUSE) 
    sub echo{ say @_ } 
} 

my $package_name = 'MyPackage'; 
$package_name->echo; 

my $object = $package_name->new(); 
$object->echo; # effectively the same as MyPackage::echo($object) 
MyPackage 
MyPackage=HASH(0x1e2a070) 

आप एक invocant के बिना एक सबरूटीन कॉल करना चाहते हैं, तो आप इसे दूसरे तरीके से कॉल करने के लिए की आवश्यकता होगी।

{ 
    no strict 'refs'; 
    ${$package_name.'::'}{echo}->('Hello World'); 
    &{$package_name.'::echo'}('Hello World'); 
} 

# only works for packages without :: in the name 
$::{$package_name.'::'}{echo}->('Hello World'); 

$package_name->can('echo')->('Hello World'); 
  • can विधि सबरूटीन कि अगर यह invocant पर बुलाया गया था कहा जा सकता है के लिए एक संदर्भ देता है। कोडेफ को अलग से इस्तेमाल किया जा सकता है।

    • can पैकेज द्वारा ओवरराइड किया जा सकता है, या किसी भी वर्ग है जिसमें से यह विरासत में:

      my $code_ref = $package_name->can('echo'); 
      $code_ref->('Hello World'); 
      

      can उपयोग करने के लिए कुछ चेतावनियां हैं।

    • पैकेज को परिभाषित करने वाला पैकेज आक्रमणकारी से अलग हो सकता है।


    यह वास्तव में वह व्यवहार हो सकता है जिसे आप ढूंढ रहे हैं।

  • एक अन्य दृष्टिकोण symbolic reference नामक किसी चीज़ का उपयोग करना है।

    { 
        no strict 'refs'; 
        &{ $package_name.'::echo' }('Hello World'); 
    } 
    

    प्रतीकात्मक संदर्भों का उपयोग आमतौर पर अनुशंसित नहीं किया जाता है। समस्या का एक हिस्सा यह है कि गलती से एक प्रतीकात्मक संदर्भ का उपयोग करना संभव है जहां आप एक का उपयोग करने का इरादा नहीं रखते थे। यही कारण है कि आप use strict 'refs'; प्रभाव में नहीं हो सकते हैं।

    यह करने का सबसे आसान तरीका हो सकता है कि आप क्या करना चाहते हैं।

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

    $MyPackage::{echo}->('Hello World'); 
    $::{'MyPackage::'}{echo}->('Hello World'); 
    
    $main::{'MyPackage::'}{echo}->('Hello World'); 
    $main::{'main::'}{'MyPackage::'}{echo}->('Hello World'); 
    $main::{'main::'}{'main::'}{'main::'}{'MyPackage::'}{echo}->('Hello World'); 
    

    इस के साथ समस्या सिर्फ आप पर $package_name विभाजित करने के लिए ::

    *Some::Long::Package::Name::echo = \&MyPackage::echo; 
    
    $::{'Some::'}{'Long::'}{'Package::'}{'Name::'}{echo}('Hello World'); 
    
    sub get_package_stash{ 
        my $package = shift.'::'; 
        my @package = split /(?<=::)/, $package; 
        my $stash = \%:: ; 
        $stash = $stash->{$_} for @package; 
        return $stash; 
    } 
    get_package_stash('Some::Long::Package::Name')->{echo}('Hello World'); 
    

    यह हालांकि कि एक समस्या का बड़ा नहीं है के लिए होता है। CPAN पर त्वरित रूप से देखने के बाद आपको Package::Stash मिल जाएगा।

    use Package::Stash; 
    my $stash = Package::Stash->new($package_name); 
    my $coderef = $stash->get_symbol('&echo'); 
    $coderef->('Hello World'); 
    


यह ऐसा है से आयात किया गया था, सबरूटीन/विधि के उपनाम के बनाने के लिए भी संभव है (Package::Stash की Pure Perl संस्करण प्रतीकात्मक संदर्भ, नहीं छिपाने की जगह का उपयोग करता है) एक मॉड्यूल जो Exporter का उपयोग कर रहा था:

*echo = \&{$package_name.'::echo'}; 
echo('Hello World'); 

मैं आर ecommend हालांकि उर्फ ​​के दायरे को सीमित:

{ 
    local *echo = \&{$package_name.'::echo'}; 
    echo('Hello World'); 
} 

यह एक अपवाद है, जहां आप strict 'refs' को सक्षम करने पर एक प्रतीकात्मक संदर्भ का उपयोग कर सकते है।

+0

व्यापक उत्तर के लिए धन्यवाद। मैंने इसे स्वीकार कर लिया है क्योंकि आपने जो कुछ पूछा है, उसे करने के कई तरीके प्रदान किए हैं। मुझे विशेष रूप से 'कर' दृष्टिकोण पसंद है। – Sam

+1

@ सैम, 'कर' गलत है। यह विरासत के पेड़ की जांच करता है। विधियों के लिए 'can' है। – ikegami

8

ऐसा लगता है कि आप वास्तव में इसे एक विधि के रूप में नहीं कहना चाहते हैं, लेकिन नियमित सबराउटिन के रूप में। के रूप में perldoc perlref में जब अपसंदर्भन ऑपरेटरों लिस्टिंग पर विचार-विमर्श

my $package_name = 'MyPackage'; 
{ 
    no strict 'refs'; 
    &{ $package_name . '::echo' }('Hello World'); 
} 
+0

+1;" परिशुद्धता – DVK

+2

यदि आप '$ :: {$ package_name। '::'} {echo} 'का उपयोग करते हैं, तो आपको' सख्त 'रेफरी' का उपयोग करने की आवश्यकता नहीं है;' –

1

, एक उप जिसका नाम अभिव्यक्ति है बुलाने की &{ <EXPRESSION> }() वाक्य रचना का उपयोग करें:: उस मामले में, आप एक प्रतीकात्मक संदर्भ का उपयोग कर सकते

बेशक, यह है एक छोटे से मूर्खतापूर्ण इस मामले में curlies उपयोग करने के लिए है, लेकिन ब्लॉक किसी भी मनमाने ढंग से अभिव्यक्ति शामिल कर सकते हैं, विशेष रूप से, subscripted भाव में:

&{ $dispatch{$index} }(1,2,3); # call correct routine 

रैंडम व्यावहारिक उदाहरण:

# Note no "use strict"! 
use File::Slurp; 
my $p="File::Slurp"; 
@a=&{"${p}::read_file"}(".profile"); 
print $a[0]; 
संबंधित मुद्दे

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