使用eval初始化perl变量

时间:2011-09-21 21:18:17

标签: perl variables scope eval

我猜这对于那些了解Perl的人来说应该是显而易见的,但我根本就没有得到它......我也猜测它与Perl scoping « darkness中描述的问题有关 - 但是我无法应用任何在我的情况下。

无论如何,这是代码:

#!/usr/bin/env perl
# call with:
# ./test.pl

use strict;

my $tvars = "my \$varA = 1;
my \$varB = 2;
my \$varC = 3;
";

my @lines = split /\n/, $tvars;
foreach my $line (@lines) {
  print "$line\n";
  eval $line; warn $@ if $@;
}

#~ print "$varA\n"; # Global symbol "$varA" requires explicit package name at ./test.pl line 18.
#~ print "$varB\n"; # Global symbol "$varB" requires explicit package name at ./test.pl line 19.
#~ print "$varC\n"; # Global symbol "$varC" requires explicit package name at ./test.pl line 20.

$tvars = "our \$varA = 1;
our \$varB = 2;
our \$varC = 3;
";

@lines = split /\n/, $tvars;
foreach my $line (@lines) {
  print "$line\n";
  eval $line; warn $@ if $@;
}

print "$varA\n"; # Global symbol "$varA" requires explicit package name at ./test.pl line 33.
print "$varB\n"; # Global symbol "$varB" requires explicit package name at ./test.pl line 34.
print "$varC\n"; # Global symbol "$varC" requires explicit package name at ./test.pl line 35.

简单来说,我希望将“$varA = 1;”这样的内容写成字符串(文本文件);我希望perleval,以便之后我可以在同一个脚本中访问变量“$varA” - 当我尝试访问变量后,我得到的错误eval位于上述代码的注释中(但是,eval期间未报告任何警告)。 (我猜,如果eval在与主脚本不同的上下文中运行,那么我需要的是“全局”变量吗?

我该怎么做呢?我是否必须完成所有的包定义业务,即使是像上面这样的简单脚本?

非常感谢任何答案,
干杯!

3 个答案:

答案 0 :(得分:13)

它与范围有关。变量在eval表达式中使用my声明。这使它们成为eval语句的本地语句,并且在eval语句退出后无法访问。不过,您可以先声明它们:

my ($varA, $varB, $varC);  # declare outside the eval statement

my $tvars = "\$varA = 1;
\$varB = 2;
\$varC = 3;
";

eval $tvars;
# local $varA, $varB, $varC variables are now initialized

或按照您的建议,您可以使用全局变量。最简单的(虽然不一定是“最佳”方式)是将::添加到所有变量名称并将其放入主包中。

my $tvars = "\$::varA = 1;
\$::varB = 2;
\$::varC = 3;
";

eval $tvars;
print "A=$::varA, B=$::varB, C=$::varC\n";

现在,当您在示例中尝试our个变量时,实际上是在初始化包(全局)变量。但是在eval语句之外,您仍然需要限定它们(即指定包名称)才能访问它们:

$tvar = "our \$foo = 5";
eval $tvar;

print $main::foo;    # ==> 5

答案 1 :(得分:2)

问题是,当你执行eval $string时,$string被评估为自己的子程序,它有自己的词法范围。来自perldoc -f eval

In the first form [in which the argument is a string], the return value of EXPR is parsed and 
executed as if it were a little Perl program. The value of the expression (which is itself 
determined within scalar context) is first parsed, and if there were no errors, executed in the 
lexical context of the current Perl program, so that any variable settings or subroutine and format 
definitions remain afterwards.

所以,换句话说,如果你有:

use strict;
use warnings;
eval "my $foo=5;";
print "$foo\n";

你会收到错误:

Global symbol "$foo" requires explicit package name at -e line 3.
Global symbol "$foo" requires explicit package name at -e line 4.

但是,如果您首先初始化变量,那就没事了。

use strict;
use warnings;
my $foo;
eval "\$foo=5;";
print "$foo\n"; #prints out 5, as expected.

答案 2 :(得分:0)

jjolla,您可以使用require $filename;require "filename";来包含具有perl语法的文件。这将声明你需要作为全局变量的任何变量。但与往常一样,要小心Globals。