2010-01-13 6 views
17

ठीक है, मेरे पास निम्न कोड है:पर्ल फोरैच वैरिएबल असाइनमेंट सरणी में मानों को संशोधित क्यों कर रहा है?

use strict; 
my @ar = (1, 2, 3); 
foreach my $a (@ar) 
{ 
    $a = $a + 1; 
} 

print join ", ", @ar; 

और आउटपुट?

2, 3, 4

बिल्ली क्या है? वह ऐसा क्यों करता है? क्या यह हमेशा होता है? क्या वास्तव में एक स्थानीय चर नहीं है? वे कहां सोच रहे हैं?

+12

FWIW पर मेरे लिए काम करता है, इस व्यवहार perlsyn मैनपेज में दर्ज है: http://perldoc.perl.org/perlsyn.html#Foreach-Loops – friedo

+6

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

उत्तर

23

पर्ल में इनमें से बहुत सी अजीब सिंटैक्स चीजें हैं जो सामान्य कार्यों को सरल बनाती हैं (जैसे किसी सूची में पुनरावृत्ति करना और सामग्री को किसी तरह से बदलना), लेकिन अगर आप उनसे अवगत नहीं हैं तो आप यात्रा कर सकते हैं।

$a सरणी में मूल्य पर एलियास है - यह आप पाश अंदर सरणी संशोधित करने के लिए अनुमति देता है। यदि आप ऐसा नहीं करना चाहते हैं, तो $a को संशोधित न करें।

+0

यह बताने के लिए धन्यवाद कि उन्होंने इसे इस तरह से बनाने का फैसला क्यों किया। – tster

9

$a इस मामले में सरणी तत्व को एक उपनाम है। बस अपने कोड में $a = की जरूरत नहीं है और आप सरणी बदलाव नहीं करेगी। :-)

यदि मुझे सही याद है, map, grep, सभी के समान एलियासिंग व्यवहार है।

22

perldoc perlsyn देखें:

सूची के किसी भी तत्व एक lvalue है, तो आप इसे पाश अंदर वीएआर को संशोधित करके संशोधित कर सकते हैं। इसके विपरीत, यदि LIST का कोई तत्व एक आभासी नहीं है, तो उस तत्व को संशोधित करने का कोई भी प्रयास विफल हो जाएगा। दूसरे शब्दों में, foreach पाश सूचकांक चर सूची में प्रत्येक आइटम है कि आप अधिक पाशन कर रहे हैं के लिए एक अंतर्निहित उर्फ ​​है।

वहाँ कुछ भी नहीं है अजीब या अजीब एक प्रलेखित भाषा सुविधा के बारे में हालांकि मैं यह अजीब है कि कितने लोगों मना व्यवहार वे नहीं समझते का सामना पर डॉक्स जाँच मिल रहा है।

+4

+1 "मुझे यह अजीब लगता है कि कितने लोग किसी भी दस्तावेज़ीकरण को पढ़ने से इनकार करते हैं"। :-P –

+16

कुछ दस्तावेज क्यों नहीं किया जा सकता है भले ही इसे दस्तावेज किया गया हो। क्या होगा अगर भाषा के स्पेक ने कहा कि रिटर्न स्टेटमेंट के बाद एक ही कथन निष्पादित किया जाएगा, लेकिन 1 से अधिक नहीं। यह अजीब और दस्तावेज दोनों होगा। अजीब राय का विषय है। – tster

3

यहां महत्वपूर्ण अंतर यह है कि जब आप एक for लूप के प्रारंभ अनुभाग में एक my चर घोषित, यह दोनों स्थानीय लोगों और lexicals के कुछ गुणों का हिस्सा लगता है (आंतरिक देखभाल के अधिक ज्ञान को स्पष्ट करने के साथ किसी?)

my @src = 1 .. 10; 

for my $x (@src) { 
    # $x is an alias to elements of @src 
} 

for (@src) { 
    my $x = $_; 
    # $_ is an alias but $x is not an alias 
} 

इस के दिलचस्प दुष्प्रभाव यह है कि पहले मामले में, एक sub{} परिभाषित भीतर पाश के लिए चारों ओर सूची $x की जो भी तत्व के लिए उपनामित गया था एक बंद है। यह जानने के लिए, यह (हालांकि थोड़ा अजीब) एक aliased मूल्य जो भी एक वैश्विक है, जो मुझे नहीं लगता कि किसी अन्य निर्माण के साथ संभव है हो सकता है चारों ओर बंद करने के लिए संभव है।

our @global = 1 .. 10; 
my @subs; 
for my $x (@global) { 
    push @subs, sub {++$x} 
} 

$subs[5](); # modifies the @global array 
+0

पुन: "मुझे लगता है कि किसी भी अन्य निर्माण के साथ संभव नहीं है"। निश्चित रूप से आपने पर्ल मोटो टिमटोटीडी (http://en.wikipedia.org/wiki/TIMTOWTDI) के बारे में सुना है। एक सरणी तत्व को रेफरी प्राप्त करें: 'मेरा $ g5r = \ $ वैश्विक [5]; $ {$ G5r} ++; '। एक वैश्विक के साथ उपनाम बनाना: 'हमारे $ जी 5; * जी 5 = \ $ वैश्विक [5]; $ G5 ++; '। इसे स्थानीयकरण और उप-उप: 'sub doSubOnRef (& \ $) {स्थानीय $ _; * _ = $ _ [1]; $ _ [0] ->()} doSubOnRef {$ _ ++} $ वैश्विक [5]; '। यह जांचकर कि वे सभी एक ही बात का संदर्भ लेते हैं: 'my @equality = map {$ _ == \ $ वैश्विक [5]} \ $ वैश्विक [5], \ $ g5, $ g5r, doSubOnRef {\ $ _} $ वैश्विक [5]; ' –

+0

@Chris => अंतर यह है कि मेरे उदाहरण में,' $ subs [5] 'उपनाम के आस-पास एक बंद है, जो वैश्विक होने का भी होता है (लेकिन होना नहीं है)। मेरा मुद्दा यह था कि मुझे उपनाम के आसपास बंद करने के लिए किसी भी अन्य तरीके से अवगत नहीं था (केवल कोर का उपयोग करके)।आपके उदाहरण में, doSubOnRef से बंद करने का कोई तरीका नहीं है, क्योंकि टाइपग्लोब उपनाम/स्थानीय केवल पैकेज चर पर लागू होते हैं, जो (उपर्युक्त को छोड़कर) –

+0

पर बंद नहीं हो सकते हैं, यह बहुत हल्का वजन नहीं है, लेकिन यह किया जा सकता है एक बंधे लेक्सिकल के साथ: @subs_ आपके @subs के बराबर है: 'पैकेज TiedScalarRef; टाई :: स्केलर की आवश्यकता है; हमारे @ISA = qw (टाई :: StdScalar); उप फ़ेच {$ {$ _ [0] -> सुपर :: फ़ेच (@_)}} उप स्टोर {$ {$ _ [0] -> सुपर :: फ़ेच ($ _ [0])} = $ _ [ 1]} 'और' पैकेज मुख्य; मेरे @subs_; मेरे $ i (0..9) के लिए {मेरा $ आर; टाई $ आर, 'TiedScalarRef', \ $ वैश्विक [$ i]; पुश @subs_, उप {++ $ आर}} $ subs_ [5](); ' –

4

जैसा कि अन्य ने कहा है, यह दस्तावेज है।

मेरे समझ के साथ कि @_, for, map और grep की अलियासिंग व्यवहार एक गति और स्मृति अनुकूलन के साथ ही रचनात्मक के लिए दिलचस्प संभावनाएं प्रदान प्रदान करता है।अनिवार्य रूप से, निर्माण के ब्लॉक का पास-बाय-रेफरेंस आमंत्रण होता है। यह अनावश्यक डेटा प्रतिलिपि से बचकर समय और स्मृति बचाता है।

use strict; 
use warnings; 

use List::MoreUtils qw(apply); 

my @array = qw(cat dog horse kanagaroo); 

foo(@array); 


print join "\n", '', 'foo()', @array; 

my @mapped = map { s/oo/ee/g } @array; 

print join "\n", '', 'map-array', @array; 
print join "\n", '', 'map-mapped', @mapped; 

my @applied = apply { s/fee//g } @array; 

print join "\n", '', 'apply-array', @array; 
print join "\n", '', 'apply-applied', @applied; 


sub foo { 
    $_ .= 'foo' for @_; 
} 

नोट List::MoreUtilsapply समारोह का उपयोग। यह map जैसा काम करता है लेकिन संदर्भ का उपयोग करने के बजाय, विषय चर की एक प्रति बनाता है। आप की तरह कोड लिखने से नफरत है: के लिए बाहर देखने के लिए

my @foo = apply { s/foo/bar/ } @bar; 

कुछ:

my @foo = map { my $f = $_; $f =~ s/foo/bar/ } @bar; 

आप apply पसंद आएगी, जो इसे में करता है तो आप पढ़ सकते हैं पारित केवल इन निर्माणों में से एक में महत्व देता है कि इसके इनपुट मानों को संशोधित करता है, आपको "केवल पढ़ने योग्य मान का प्रयास" त्रुटि मिल जाएगी।

perl -e '$_++ for "o"' 
0

आपका $ एक बस आप इसे ऊपर लूप के रूप में सूची के प्रत्येक तत्व के लिए एक उपनाम के रूप में इस्तेमाल किया जा रहा है। इसका उपयोग $ _ के स्थान पर किया जा रहा है। आप बता सकते हैं कि $ एक स्थानीय चर नहीं है क्योंकि इसे ब्लॉक के बाहर घोषित किया गया है।

यह और अधिक स्पष्ट है कि अगर आप इसे $ _ (जो भी है) में खड़े होने के बारे में सोचते हैं तो सूची में सामग्री को बदलने के लिए असाइन करना क्यों है। वास्तव में, यदि आप अपना खुद का इटरेटर इस तरह परिभाषित करते हैं तो $ _ मौजूद नहीं है।

foreach my $a (1..10) 
    print $_; # error 
} 

आप सोच रहे हैं कि क्या बात है, मामले पर विचार: $ के लिए एक दोस्ताना नाम प्रदान करने के लिए _

my @row = (1..10); 
my @col = (1..10); 

foreach (@row){ 
    print $_; 
    foreach(@col){ 
     print $_; 
    } 
} 

इस मामले में इसे और अधिक पठनीय है में

foreach my $x (@row){ 
    print $x; 
    foreach my $y (@col){ 
     print $y; 
    } 
} 
0

foreach my $a (@_ = @ar) 

अब मोड का प्रयास करें ifying $ a @ar को संशोधित नहीं करता है। v5.20.2

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