2010-11-03 15 views
10

मुझे हमेशा यकीन था कि अगर मैं एक पर्ल सबराउटिन को एक साधारण स्केलर पास करता हूं, तो यह सबराउटिन के बाहर अपना मूल्य कभी नहीं बदल सकता है। यही कारण है:पर्ल सबराउटिन में @_ कैसे काम करता है?

my $x = 100; 
foo($x); 
# without knowing anything about foo(), I'm sure $x still == 100 

तो अगर मैं foo() चाहते x बदलने के लिए, मैं इसे x के लिए एक संदर्भ से गुजरना होगा।

तब मुझे पता चला कि यह स्थिति नहीं है:

sub foo { 
$_[0] = 'CHANGED!'; 
} 
my $x = 100; 
foo($x); 
print $x, "\n"; # prints 'CHANGED!' 

और एक ही सरणी तत्वों के लिए चला जाता है:

my @arr = (1,2,3); 
print $arr[0], "\n"; # prints '1' 
foo($arr[0]); 
print $arr[0], "\n"; # prints 'CHANGED!' 

कि थोड़े मुझे हैरान कर दिया। यह कैसे काम करता है? क्या subroutine केवल मान तर्क के साथ प्राप्त नहीं होता है? यह इसका पता कैसे जानता है?

+5

पर्ल सी नहीं है। सी की तरह व्यवहार करने की अपेक्षा न करें, या सी ++ या जावा जैसी सी-व्युत्पन्न भाषा। –

+9

[perldoc perlsub] (http://perldoc.perl.org/perlsub.html) – Ether

+1

आपका प्रश्न '@ _',' _ _' नहीं है। और 'उप' में '@ _' में अक्सर मानों की प्रतियों के बजाय उपनाम होते हैं। इसलिए यदि आप इस व्यवहार को अपने 'उप' में नहीं चाहते हैं, तो शुरुआत में '@ _' से' my' चर से इनपुट कॉपी करना सुनिश्चित करें। – aschepler

उत्तर

19

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

इस उप में तो

:

sub example { 
    # @_ is an alias to the arguments 
    my ($x, $y, @rest) = @_; # $x $y and @rest contain copies of the values 
    my $args = \@_; # $args contains a reference to @_ which maintains aliases 
} 

ध्यान दें कि यह अलियासिंग सूची में विस्तार के बाद होता है, इसलिए यदि आप example को एक सरणी पारित कर दिया, सरणी सूची संदर्भ में फैलता है, और @_ प्रत्येक तत्व के अन्य नामों पर सेट किया गया है सरणी का (लेकिन सरणी स्वयं example पर उपलब्ध नहीं है)। यदि आप उत्तरार्द्ध चाहते थे, तो आप सरणी के संदर्भ को पारित करेंगे।

सबराउटिन तर्कों का एलिसिंग एक बहुत ही उपयोगी विशेषता है, लेकिन देखभाल के साथ इसका उपयोग किया जाना चाहिए। बाह्य चर के अनपेक्षित संशोधन को रोकने के लिए, पर्ल 6 में आपको यह निर्दिष्ट करना होगा कि आप is rw के साथ लिखने योग्य एलियाज्ड तर्क चाहते हैं।

my $slice = sub {\@_}->(@somearray[3 .. 10]); 

यह भी है कि करने के लिए sub {\@_}->(LIST) का उपयोग कर पता चला:

कम ज्ञात लेकिन उपयोगी चाल में से एक उपनाम

my ($x, $y) = (1, 2); 

my $alias = sub {\@_}->($x, $y); 

$$alias[1]++; # $y is now 3 

की सरणी refs या एलियास स्लाइस बनाने के लिए इस अलियासिंग सुविधा का उपयोग करने है सूची से एक सरणी बनाना वास्तव में
[ LIST ] से तेज़ है क्योंकि पर्ल को प्रत्येक मान की प्रतिलिपि बनाने की आवश्यकता नहीं है। निस्संदेह नकारात्मक (या आपके परिप्रेक्ष्य के आधार पर उल्टा) यह है कि मूल्य अलियाकृत रहते हैं, इसलिए आप मूल को बदलने के बिना उन्हें बदल नहीं सकते हैं।

रूप tchrist एक और जवाब देने के लिए एक टिप्पणी में उल्लेख है, आप पर्ल के अलियासिंग निर्माणों में से किसी का उपयोग करते हैं @_ पर, $_ वे प्रदान है कि आप भी मूल सबरूटीन तर्कों को एक उपनाम है। जैसे:

sub trim {s!^\s+!!, s!\s+$!! for @_} # in place trimming of white space 

अन्त में सभी इस व्यवहार का nestable है, इसलिए जब एक और सबरूटीन का तर्क सूची में @_ का उपयोग कर (या इसे का एक टुकड़ा), यह भी पहली सबरूटीन के तर्कों को उपनाम हो जाता है:

sub add_1 {$_[0] += 1} 

sub add_2 { 
    add_1(@_) for 1 .. 2; 
} 
2

पर्ल संदर्भ द्वारा तर्कों को पास करता है, मूल्य से नहीं। http://www.troubleshooters.com/codecorn/littperl/perlsub.htm

+1

+1, लेकिन इसके अलावा संदर्भ तोड़ता है यदि ओपी इसके बजाय 'मेरा $ notref = $ _ [0] लिखता है; $ notref = 'unchanged!'; 'यह (और पठनीय नामों का अतिरिक्त लाभ) यही कारण है कि अधिकांश सबराउटिन नामित चरों में '@ _' में सभी आइटम असाइन करके प्रारंभ करते हैं। –

+4

आपके द्वारा लिंक किया गया दस्तावेज़ 2003 से अपडेट नहीं किया गया है, जो 5.8.8 की भविष्यवाणी करता है, जिसे अक्सर पर्ल के सबसे पहले "अनुशंसित अनुमत" संस्करण माना जाता है। इसमें से अधिकांश अभी भी सटीक है, लेकिन कुछ स्थितियां होंगी जहां वाक्यविन्यास बदल दिया गया है या सुधार हुआ है। – Ether

+2

पर नवीनतम persub का प्रयास करें: http://perldoc.perl.org/perlsub.html या इसे आप एक पुराने संस्करण हैं: http://perldoc.perl.org/5.8.8/perlsub.html – daotoad

11

यह सब perldoc perlsub में विस्तार से दस्तावेज किया गया है। उदाहरण के लिए:

सरणी @_ में दिखाए गए किसी भी तर्क को पारित किया गया। इसलिए, यदि आपने दो तर्कों के साथ फ़ंक्शन कहा है, तो उन्हें $ _ [0] और $ _ [1] में संग्रहीत किया जाएगा। सरणी @_ एक स्थानीय सरणी है, लेकिन इसके तत्व वास्तविक स्केलर पैरामीटर के लिए उपनाम हैं। विशेष रूप से, यदि कोई तत्व $ _ [0] अपडेट किया गया है, तो संबंधित तर्क अपडेट किया गया है (या त्रुटि तब होती है जब यह अद्यतन करने योग्य नहीं है)। यदि कोई तर्क एक सरणी या हैश तत्व है जो फ़ंक्शन को कॉल करने के दौरान मौजूद नहीं था, तो वह तत्व केवल तभी बनाया जाता है जब (और यदि) इसे संशोधित किया गया हो या इसका संदर्भ लिया गया हो। (पर्ल के कुछ पुराने संस्करणों ने तत्व बनाया है या नहीं, तत्व को असाइन किया गया था या नहीं।) पूरे सरणी को असाइन करना @_ उस अलियासिंग को हटा देता है, और किसी भी तर्क को अद्यतन नहीं करता है।

+2

किसी ने कि उल्लेख करना चाहिए एलियासिंग संक्रमणीय है, जैसे 'के लिए (@_) {s/^ \ s + //; एस/\ एस + $ //} '। – tchrist