【问题标题】:perl eval Use of uninitialized value declared in packageperl eval 使用包中声明的未初始化值
【发布时间】:2015-09-01 11:47:23
【问题描述】:

谁能向我解释一下为什么在包中声明的变量不能被 eval 函数访问,除非它在子程序中使用一次?
(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" ;

执行程序时的结果:

在连接 (.) 或字符串中使用未初始化的值 $insertVar 在 (eval 1) 第 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;

然后程序完全按照我的预期运行:

测试

insertVar = 测试

【问题讨论】:

  • 你到底为什么要eval分配一个变量来设置自己?

标签: perl scope package eval lexical


【解决方案1】:

当文件完成执行时(在requireuse 返回之前),文件中声明的变量(在花括号之外)超出范围。

$insertVar 只有在文件执行完毕后被 sub 捕获后才会继续存在,并且只有捕获它的 sub 才能看到它。

出于效率原因,subs 捕获尽可能少的变量。如果 sub 没有引用 $insertVar,它将不会捕获它。由于您的第一个 testSub 没有引用 $insertVar,因此它不会捕获它。由于在您调用testSub$insertVar 已超出范围,因此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

【讨论】:

  • 正确的答案可能是向这个人展示如何访问包变量。这是一个 XY 问题。
  • @TLP,我做到了,但应该使用适当的模板系统。
  • ikegami,已接受并感谢您的明确回答,关于 sub 如何捕获变量的部分是我正在寻找的答案。我只是无法理解这里发生了什么。 TLP,我知道“我们的”,并且它使问题消失了。我更喜欢 ikegami 的回答,因为他向我解释了包中变量的生命周期是如何使用“my”声明的。
猜你喜欢
  • 2011-07-19
  • 1970-01-01
  • 2013-04-08
  • 1970-01-01
  • 2016-09-25
  • 2015-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多