2009-06-18 42 views
7

所以,我從來不知道這一點,我想對其進行澄清。我知道如果你這樣做

foreach (@list){ 

如果你在該循環中更改$ _它將影響實際數據。但是,我不知道如果你做了

foreach my $var1 (@list){ 

如果你在循環中更改了$ var1,它會改變實際的數據。 : - /所以,有沒有辦法循環@list,但保持變量只讀副本,或副本,如果更改不會更改@list中的值?

回答

10

$var依次替換每個項目。

http://perldoc.perl.org/perlsyn.html#Foreach-Loops

如果列表的任何元素是左值,你可以通過修改環路內VAR修改。相反,如果LIST的任何元素不是左值,則任何修改該元素的嘗試都將失敗。換句話說,foreach循環索引變量是列表中每個要循環的 項目的隱式別名。

8

最簡單的方法就是將它複製:

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

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

但如果$ VAR1是一個參考,$ var1_scratch將是同樣的事情的參考。 要想獲得真正的安全,你必須使用像耐儲藏:: dclone做一次深層副本:

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

(未經測試)。那麼你應該能夠安全地更改$ var1。但是如果 @list是一個很大的數據結構,它可能會很昂貴。

+1

小心,$ VAR1不是一個參考,但一個別名。看到區別: my $ var2 = \ $ list [0];打印「$ var2 \ n」; 顯示SCALAR(0x8171880) – wazoox 2009-06-18 16:17:09

+3

@wazoox:他的意思是如果$ var1包含一個引用,例如,如果@list包含一堆HASH引用。即使你打破了別名,你仍然有另一個對同一事物的引用副本。 – 2009-06-18 16:29:12

1

我不知道如何在foreach語句本身中強制變量爲by-value而不是by-reference。您可以複製$_的值。

#!/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

你說'my $ v = shift',`你的意思是`我的$ v = $ _;`。 – dave4420 2009-06-18 15:42:24

+0

@Dave Hinton糾正了錯誤。 @Sukotto嘗試在您的循環體中打印$ v,就像您最初編寫它以查看錯誤一樣。 – 2009-06-18 15:58:44

4

它是一個別名,而不是參考。如果你想創建你自己的別名(在for之外),你可以使用Data::Alias

2

這些環之間的唯一區別:

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

是循環變量。別名是foreach的函數,而不是隱式變量$_。請注意,這是一個別名(同一事物的另一個名稱),而不是參考(指向某物的指針)。

在簡單(普通)的情況下,你可以通過副本打破別名:

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

這適用於普通標量值。對於參考文獻(或對象),您需要使用StorableClone進行深層複製,這可能會很昂貴。被綁定的變量也是有問題的,perlsyn建議完全避免這種情況。

0

讓@list的副本for語句:

foreach my $var1 (() = @list) { 
    # modify $var without modifying @list here 
}