2010-08-21 98 views
7

我以爲我理解地圖,但以下結果,我不明白。我知道爲什麼會發生,我只是不知道它是如何發生的。

問題是@array的內容正在改變,因爲在調用_do_stuff_to_file期間正在重置$_。所以當我預計它是here: donkie\nhere: kong\n時,打印的是here: \nhere:\n

說明:這是未經測試的代碼。這正是我記得從實驗室看到的。爲什麼@array的內容有變化?

如果我將$_設置爲$f,然後再從_some_func返回1。然後數組仍然完好無損。

下面是一個例子程序來說明我所看到的:

​​
+3

您的問題已經包含了自己的答案 - 您已經解釋了它是如何發生的。你是否想改變你的問題到「我該如何避免讓東西暴露$ _'?因爲那是我們可以回答的問題(而且邁克爾卡爾曼已經有了) – hobbs 2010-08-21 22:02:05

+0

我同意hobbs提出的問題標題@yesterday Could you更改它? – dolmen 2010-08-23 10:03:10

回答

9

在Perl的許多功能使用默認的變量$_。其中有map和readline運算符<>。與foreach一樣,map使循環變量成爲它處理的列表的每個元素的別名。發生了什麼事的是,這條線:

while (<IN>) 

被分配到$_map的混疊生效。這是使用$_(或任何其他全局變量)的問題之一 - 遠處的奇怪動作。如果你要使用$_,第一定位吧:

local $_; 
while (<IN>) 
... 

或者,改爲使用詞法變量:

while (my $line = <IN>) 
+0

但爲什麼使用$ _更改數組的內容?isnt $ _只是一個變量,它是數組當前值的副本? – user318747 2010-08-21 22:02:02

+0

好吧我現在看到了,謝謝。 – user318747 2010-08-21 22:04:12

4

修改$ _會改變你的初始陣列,因爲$ _是一個別名到當前元素。您的代碼應如下所示:

my @array = ("donkie", "kong"); 
my @junk=map {_some_func('blah', $_) } @array; 

if (join ('', @junk) !~ /0/) 
{ # for example sake this is always true since return 1 from _some_func. 
    print map { "here: $_\n"; } @array; 
} 

sub _some_func 
{ # for example sake, lets say $f always exists as a file. 
    my $j = shift; 
    my $f = shift; 
    return 0 if !-e $f; 
    _do_stuff_to_file($f); 
    return 1; 
} 


sub _do_stuff_to_file 
{ 
    my $f = shift; 
    local $_; 
    open(IN, "<",$f); 
    open(OUT, ">", "$f.new"); 

    while (<IN>) 
    { 
     print OUT; 
    } 

    close IN; 
    close OUT; 
} 

P.S. map返回具有相同元素數量的數組(如果標量是從塊返回的)。 grep只返回block爲true的元素。

+1

列表'map'返回不一定具有與其輸入相同數量的元素,例如'@doubled = map {$ _,$ _}(1..5)' – 2010-08-22 13:45:55

0

我同意Alexander和Michael的答案:_do_stuff_to_file()正在改變$_的值。 在map的上下文中,$_只是存儲映射元素的名稱,數組已更改。

Alexander和Michael建議更改_do_stuff_to_file(),以免影響$_值。本地化特殊變量(如$_)以避免擾亂外部範圍是一種很好的做法。

下面是避免接觸該功能的一個替代解決方案:

map { my $x=$_; local $_; push @junk, _some_func('blah', $x); } @array; 

或多個以下的常見樣式:

「中斷」由本地定義映射塊內的鏈接調用函數之前
@junk = map { my $x=$_; local $_; _some_func('blah', $x) } @array; 
+0

或'my $ _;'在地圖之前會導致地圖使用(5.10+) – ysth 2010-08-22 18:23:56

+0

@ysth「my $ _」將創建一個新的變量,以語法形式映射到地圖塊,但不會影響_some_func()和_do_stuff_to_file()上下文,所以這不會影響解決問題。 – dolmen 2010-08-23 10:04:01

+0

是的,它將解決* that * map的問題,除非您希望*他們能夠更改@array中的別名值。 – ysth 2010-08-23 13:46:18

4

設置$ _的大部分內容都會隱式別名,所以不會導致此問題;例外是while (<filehandle>)。雖然您可以本地化$ _(理想情況下爲my $_;),但最好不要隱式設置$ _。改爲while (my $line = <filehandle>)。 (特殊的隱式定義()仍然會發生。)