2015-06-16 73 views
0

中聲明的未初始化的值任何人都可以向我解釋爲什麼在包中聲明的變量不能被eval函數訪問,除非它在sub中使用一次?
(perl的v5.16.3 MSWin32-64的多線程的ActiveState)perl eval使用包

套餐:

use strict; 
use warnings; 
package testPackage; 
my $insertVar = "TEST"; 
sub testSub { 
    my $class = shift; 
    my $test = shift; 
    eval '$test="'.$test.'";'; 
    return $test; 
} 
1; 

計劃:

use strict ; 
use warnings ; 
use testPackage ; 
my $testVar = q[insertVar = ${insertVar}] ; 
$testVar = testPackage->testSub($testVar) ; 
print "$testVar\n" ; 

結果來執行程序時:

使用的未初始化值$ insertVar在串聯(。)或字符串中 at (eval 1)line 1. insertVar =

現在,如果我使用testSub中的變量(例如,打印出來):

use strict; 
use warnings; 
package testPackage; 
my $insertVar = "TEST"; 
sub testSub { 
    my $class = shift; 
    my $test = shift; 
    print $insertVar . "\n"; 
    eval '$test="'.$test.'";'; 
    return $test; 
} 
1; 

然後該程序運行完全一樣我打算:

TEST

insertVar = TEST在一個文件中聲明

+0

爲什麼地球上你會''評估一個變量的賦值來設置自己? – TLP

回答

1

my變量(花括號外)當文件完成執行時(在requireuse返回之前)超出範圍。

$insertVar只會在文件完成執行後纔會繼續存在,如果它被子捕獲,並且只有捕獲它的子文件纔可見。

出於效率的原因,潛艇捕獲了儘可能少的變量。如果子沒有引用$insertVar,它將不會捕獲它。由於您的第一個testSub未參考$insertVar,因此它不捕獲它。由於$insertVar在您撥打testSub時已超出範圍,因此eval不可用。您應該收到警告Variable "$insertVar" is not available,但由於我未知的原因,它會針對您使用的特定代碼發佈。

你的第二個testSub參考$insertVar,所以testSub捕獲$insertVar並保持它活着。即使$insertVar在您撥打testSub時已超出範圍,但eval可用,因爲它已被該子捕獲。

如果您使用our聲明變量,它們將是全局包變量,因此不會超出範圍,它們將可用於eval

>perl -wE"use strict; use warnings; { my $x = 'abc'; sub foo { $x } } say foo()" 
abc 

>perl -wE"use strict; use warnings; { my $x = 'abc'; sub foo { eval '$x' } } say foo()" 
Variable "$x" is not available at (eval 1) line 2. 
Use of uninitialized value in say at -e line 1. 


>perl -wE"use strict; use warnings; { our $x = 'abc'; sub foo { eval '$x' } } say foo()" 
abc 
+0

正確的答案可能是顯示此人如何訪問包變量。這是一個XY問題。 – TLP

+0

@TLP,我做到了,儘管應該使用適當的模板系統。 – ikegami

+0

ikegami,接受並感謝您的明確回答,關於變量如何被sub捕獲的部分是我正在尋找的答案。我無法理解這裏發生的事情。 TLP,我知道'我們',並且它讓問題消失。我更喜歡ikegami的答案,因爲他向我解釋了一個包中變量的生命週期如何用'my'聲明。 – Veltro