2015-01-07 60 views
4

爲什麼@coderefs中coderefs返回的$ copy_of_i的值相同?coderefs中的變量作用域if perl需要奇怪行爲的解釋

use Modern::Perl; 
my @coderefs =(); 
for (my $i = 0; $i < 5; $i++){ 
    push @coderefs, sub { 
     my $copy_of_i = $i; 
     return $copy_of_i; 
    }; 
} 

say $coderefs[1]->(); 
say $coderefs[3]->(); 

我以爲$ copy_of_i是當地每一個CODEREF加入@coderefs,因此包含在循環的給定迭代分配到$ copy_of_i $ i的當前值。但是如果我們用'say'顯示幾個$ copi_of_i的值,我們會看到它們具有相同的值,就像$ copy_of_i對於每個新創建的coderef不是本地的。爲什麼?

回答

4

您希望具有與關閉關聯的不同值,但您只有單個變量$i才能捕獲所有關閉。您需要爲每個閉包創建一個變量來捕獲,因此$copy_of_i應該在閉包之外創建。當你致電關閉時創建副本太晚了; $i不再包含該點的期望值。

for (my $i = 0; $i < 5; $i++){ 
    my $copy_of_i = $i; 
    push @coderefs, sub { 
     return $copy_of_i; 
    }; 
} 

順便說一句,for my $i (0 .. 5)優於for (my $i = 0; $i < 5; $i++),具有開創了循環的每個迭代一個新的變量的優勢,所以你可以簡單地使用

my @coderefs; 
for my $i (0 .. 4) { 
    push @coderefs, sub { 
     return $i; 
    }; 
} 
+0

非常感謝,Сухой27 !這工作。但我仍然沒有得到這個過程的機制。你能解釋爲什麼我的代碼不起作用嗎?當我在coderef主體中聲明$ copy_of_i時會發生什麼,以及爲什麼我應該改變它之外的變量呢? – Tyoma

+0

@Tyoma檢查'$ i'變量的更新和內存地址https://eval.in/240135(相同)https://eval.in/240136(不同) –

+0

問題中與for循環的等價物實際上爲我的$我(0..4)'。 – nwellnhof