2010-02-11 81 views
4

從上foreach循環的話題的perldoc perlsyn在「foreach」循環中會發生什麼樣的本地化?

如果變量之前 我宣佈,它使用 變量而不是全局的, 但它仍然定位於環。

但考慮這個例子:

use Devel::Peek; 
my $x = 1; 
Dump $x; 
for $x (1) { Dump $x } 

SV = IV(0x8117990) at 0x8100bd4 
    REFCNT = 1 
    FLAGS = (PADBUSY,PADMY,IOK,pIOK) 
    IV = 1 
SV = IV(0x8117988) at 0x8100bf8 
    REFCNT = 2 
    FLAGS = (IOK,READONLY,pIOK) 
    IV = 1 

好像這些都不是相同的變量。這是文檔中的錯誤,還是我錯過了什麼?

+1

對,現在你的問題是什麼? – amarillion 2010-02-11 21:55:19

+1

而問題是...? – 2010-02-11 21:56:07

+2

雖然你在思考這個問題,但一定要閱讀:http://perldoc.perl.org/perlsub.html#Temporary-Values-via-local%28%29,也許看看這個:http:// stackoverflow.com/questions/2238576/what-is-the-default-scope-of-foreach-loop-in-perl – 2010-02-11 22:00:05

回答

5

每個規則都需要它的例外,這是一個例外。在for循環中,如果循環變量是一個詞法(用my聲明),Perl將爲循環中的當前項創建一個新的詞法。 OP代碼可以寫成如下:

use Data::Alias 'alias'; 

my $x = 1; 
for (2..3) { 
    alias my $x = $_; 
    # note that $x does not have dynamic scope, and will not be visible in 
    # subs called from within the loop 
    # but since $x is a lexical, it can be closed over 
} 

編輯:前面的例子是在Perl僞代碼中,爲了清晰起見修改了答案。

+1

「Perl將創建詞彙的本地版本」不正確。 Perl不創建詞彙的本地版本,沒有這樣的事情,它沒有任何意義。它創建一個* global *的本地版本。在OP的情況下,詞彙和全球都稱爲$ x。你可以用這個襯墊看到它:'perl -wle'$ x = 42;爲$ x(1..5){print $ main :: x; }''vs'perl -wle'$ x = 42;爲我的$ x(1..5){print $ main :: x; }'' – Schwern 2010-02-12 08:58:57

+1

如果你明確引用'$ :: x'(全局$ x),你的代碼就可以工作。否則$ x引用聲明的詞彙$ x。 '我的$ x = 1; for(2..3){local * x = \ $ _;打印$ :: x; }'如果沒有聲明詞法$ x,那麼$ x引用全局$ x。 '$ x = 1; for(2..3){local * x = \ $ _;打印$ x; }故事的道德:不要把一個詞彙和一個同名的全球化。 – Schwern 2010-02-12 09:07:23

2

正確地,它應該被稱爲別名,以避免與local()混淆。 CPAN上有各種模塊可以讓你在其他情況下進行別名。

-1

首先,認識到存在全局(包範圍)變量並且存在詞彙變量。他們可以有相同的名字。從現在開始,我將通過其全稱爲$::x的全球$ x來表示「全球$ x包主體」的縮寫。

爲了向後兼容,for循環使用本地化的全局變量,除非您另外聲明,否則$ x已被聲明爲詞法變量(沒有意識到)。所以for $x (2..3) {}引用了一個本地化的$ :: x。 for my $x (2..3) {}涉及詞彙$ x。在這兩種情況下,他們的範圍內循環,有點像︰

for (2..3) { 
    my $x = $_; 
    ... 
} 

除$ _被別名到$ x,不復制。

我相信上面的解釋了爲什麼你在使用Devel :: Peek時會得到不同的標量。由於對於詞法沒有相應的local(),所以它可能會在for循環中的詞法板上聲明一個新的詞法,就像上面的代碼一樣。

my $original = $x; 
my $new; 
*::x = \$new; 

... 

*::x = \$original; 

即:

local($x),因爲它是做這樣的事情也改變底層的SV。製作一個新的標量,將其插入符號表的$ x插槽,然後在完成示波器時恢復舊的標量。

但這真的只是假設。你必須深入代碼才能發現。

該文檔說詞彙「本地化到循環」不應該被認爲是字面意思local()。術語local令人困惑,因爲其他語言,甚至是Perl程序員,都可以互換使用它來表示local()和「詞法作用域」。 local()可能會更好地稱爲temp()。所以我認爲這些文檔在他們的術語方面略顯sl sl。

+1

man perlsyn:...「如果變量先前用」my「聲明,它將使用該變量而不是全局變量,但它仍然侷限於循環中。」這似乎是不正確的.. – 2010-02-12 09:53:57

+1

@Schwern perlmod:「如果包名稱爲空,假設'主'包。」 – 2010-02-12 14:16:43

+0

@Eric我覺得有趣的事情正在進行,因爲與'perl -wle'$ x比較= 1;對於$ x(2..3){print「$ x vs $ :: x \ n」}'' – Schwern 2010-02-12 19:57:22