perl eval 使用包中声明的未初始化值

perl eval Use of uninitialized value declared in package

任何人都可以向我解释为什么在包中声明的变量不能被 eval 函数访问,除非它在 ​​sub 中使用一次吗?
(perl v5.16.3 MSWin32-x64-多线程 ActiveState)

包裹:

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" ;

执行程序时的结果:

Use of uninitialized value $insertVar in concatenation (.) or string 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

my 文件中声明的变量(在卷曲之外)在文件完成执行时超出范围(在 requireuse return 之前)。

$insertVar只有在文件被sub捕获后才会继续存在,并且只有捕获它的sub可见。

出于效率原因,潜艇捕获尽可能少的变量。如果 sub 没有引用 $insertVar,它就不会捕获它。由于您的第一个 testSub 没有引用 $insertVar,因此它不会捕获它。由于在您调用 testSub$insertVar 已经超出范围,因此它对 eval 不可用。您应该收到警告 Variable "$insertVar" is not available,但出于我不知道的原因,它是针对您使用的特定代码发出的。

您的第二个 testSub 引用 $insertVar,因此 testSub 捕获 $insertVar 并使其保持活动状态。尽管在您调用 testSub$insertVar 已经超出范围,但由于它被子程序捕获,因此 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