2009-06-18 13 views
7

तो, मुझे यह कभी नहीं पता था और मैं इसके बारे में कुछ स्पष्टीकरण प्राप्त करना चाहता हूं। मुझे पता है कि क्या आप

foreach (@list){ 

यदि आप उस लूप में $ _ बदलते हैं तो यह वास्तविक डेटा को प्रभावित करेगा। लेकिन, मुझे नहीं पता था कि अगर आपने

foreach my $var1 (@list){ 

यदि आपने लूप में $ var1 बदल दिया है तो यह वास्तविक डेटा बदल देगा। : -/तो, क्या @list पर लूप करने का कोई तरीका है, लेकिन चर को केवल पढ़ने-योग्य प्रतिलिपि रखें, या एक प्रतिलिपि जो बदली गई है, वह @list में मान नहीं बदलेगी?

उत्तर

10

$var बदले में प्रत्येक आइटम को अलियाकृत किया गया है।

देखें http://perldoc.perl.org/perlsyn.html#Foreach-Loops

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

8

सबसे आसान तरीका है बस इसे कॉपी करने के लिए है:

foreach my $var1 (@list) { 
    my $var1_scratch = $var1; 

या

foreach my $var1 (map $_, @list) { 

लेकिन अगर $ var1 एक संदर्भ है, $ var1_scratch एक ही बात के लिए एक संदर्भ हो जाएगा।

foreach my $var1 (@{ Storable::dclone(\@list) }) { 
} 

(untested): वास्तव में सुरक्षा के लिए, आप एक गहरी प्रतिलिपि करने के लिए Storable :: dclone की तरह कुछ का उपयोग करना होगा। फिर आप सुरक्षित रूप से $ var1 को बदलने में सक्षम होना चाहिए। लेकिन यह महंगा हो सकता है यदि @list एक बड़ा डेटास्ट्रक्चर है।

+1

सावधान रहें, $ var1 एक संदर्भ है, लेकिन एक अन्य नाम नहीं है। अंतर देखें: मेरी $ var2 = \ $ सूची [0]; प्रिंट करें "$ var2 \ n"; स्केलर (0x8171880) – wazoox

+3

@wazoox प्रदर्शित करता है: उसका मतलब था कि $ var1 में कोई संदर्भ शामिल है, उदा। यदि @list में HASH refs का एक गुच्छा शामिल है। यहां तक ​​कि यदि आप एलियासिंग तोड़ते हैं, तो भी आपके पास एक ही चीज़ के संदर्भ की एक और प्रति है। –

1

मुझे नहीं पता कि वेरिएबल को फ़ोरैच स्टेटमेंट में संदर्भ के बजाय बाय-वैल्यू को कैसे बल देना है। हालांकि आप $_ के मान की प्रतिलिपि बना सकते हैं।

#!/usr/perl/bin 
use warnings; 
use strict; 

use Data::Dumper; 

my @data = (1, 2, 3, 4); 

print "Before:\n", Dumper(\@data), "\n\n\n"; 

foreach (@data) { 
    my $v = $_; 
    $v++; 
} 

print "After:\n", Dumper(\@data), "\n\n\n"; 

__END__ 
+2

जहां आप कहते हैं 'मेरा $ v = shift;' आपका मतलब है 'मेरा $ v = $ _; '। – dave4420

+0

@ डेव हिनटन ने त्रुटि को सही किया। @ सुकोटो अपने लूप के शरीर में $ v प्रिंट करने का प्रयास करें क्योंकि आपने मूल रूप से इसे अपनी त्रुटि देखने के लिए लिखा था। –

+0

हां, मेरा मतलब था 'मेरा $ v = $ _; ':-( – Sukotto

4

यह एक उपनाम है, संदर्भ नहीं। यदि आप अपने स्वयं के उपनाम बनाना चाहते हैं (इसके बाहर) आप Data::Alias का उपयोग कर सकते हैं।

+1

उम्म ... +0। ओपी/संदर्भ स्पष्टीकरण और -1 के लिए यह +1 है जिसे ओपी ने जो कहा था उसके विपरीत करने के निर्देश दिए (एलियासिंग को तोड़ने के विरोध में एक उपनाम बनाना।) –

+0

@ माइकल कारमेन यास्ट ने पहले से ही सही उत्तर दिया था, मैं बस यह इंगित कर रहा था कि अपने स्वयं के उपनाम बनाना संभव है। –

2

इन छोरों के बीच फर्क सिर्फ इतना है:

foreach (@array) { ... } 
foreach my $var (@array) { ... } 

पाश चर रहा है। एलियासिंग foreach का एक कार्य है, निहित चर $_ नहीं। ध्यान दें कि यह उपनाम (एक ही चीज़ के लिए एक और नाम) है और संदर्भ (किसी चीज़ के लिए सूचक) नहीं है।

सरल (और सामान्य) मामले में, आप एक प्रतिलिपि बनाकर अलियासिंग तोड़ सकते हैं:

foreach my $var (@array) { 
    my $copy = $var; 
    # do something that changes $copy 
} 

यह साधारण अदिश मूल्यों के लिए काम करता है।संदर्भ (या ऑब्जेक्ट्स) के लिए आपको Storable या Clone का उपयोग करके गहरी प्रतिलिपि बनाने की आवश्यकता होगी, जो महंगा हो सकता है। बंधे हुए चर भी समस्याग्रस्त हैं, perlsyn पूरी तरह से स्थिति से परहेज करने की सिफारिश करता है।

+0

या क्लोन :: अधिक या क्लोन :: फास्ट – ysth

+0

या मेरे $ var (() = @array के साथ foreach में एक प्रतिलिपि बनाएँ – MkV

0

बयान के लिए में @list की एक कॉपी बनाएं:

foreach my $var1 (() = @list) { 
    # modify $var without modifying @list here 
} 
संबंधित मुद्दे