【发布时间】:2018-03-17 07:50:41
【问题描述】:
当eval 语句在词法变量的范围内时,该变量应该在评估块的词法上下文中。此外,词法变量应该在 subs 的词法上下文中可用。
但这不起作用:
use warnings;
{
package VLE;
my $ln10 = 2.302585092994045684017991454684;
sub reval {
say eval $_[0] if @_;
}
}
package VLE;
reval( q($ln10) );
结果:
Variable "$ln10" is not available at (eval 1) line 1.
但是如果我(无用地)在块中的任何地方使用词法变量,它会突然在 eval 中可用:
use warnings;
{
package VLE;
my $ln10 = 2.302585092994045684017991454684;
sub reval {
say eval $_[0] if @_;
my (undef) = $ln10;
return 0
}
}
package VLE;
reval( q($ln10) );
打印
2.30258509299405
为什么会这样?
编辑:
引用的破坏不是问题,因为这段代码(维护对$ln10的引用)也失败了:
use warnings;
{
package VLE;
my $ln10 = 2.302585092994045684017991454684;
sub reval2 {
say eval $_[0] if @_;
my (undef) = $ln10;
return 0
}
sub reval {
say eval $_[0] if @_;
return 0
}
}
package VLE;
reval( q($ln10) ); # still fails
reval2( q($ln10) ); # works
【问题讨论】:
-
我认为在普通括号中使用通用引号
q、qq、qx等是不好的做法。q($ln10)看起来太像一个子例程调用,并且比这里的'$ln10'好得多。即使你想引用一个包含单引号的字符串,像q/$str = 'aaa'/这样的东西会更可取,因为斜线是 Perl 常见的“替代引号”。我已经编辑了你的问题。 -
我经常使用
q(),因为我经常用perl -E '... say join("\n", split("", "foo ".q($foo))) ...'在终端中测试Perl的sn-ps,经常在' '里面有一个多行程序,包括上面两个,括号使它当单引号不可用时,易于跟踪块/引用级别,尤其是在终端中没有语法突出显示的情况下。有充分的理由去做所有你认为不好的事情。 -
我什至更喜欢不带任何单引号的 sn-ps,因为我可以将它们直接粘贴到终端中,而无需使用 heredoc。
-
我不明白你所说的 “所有 [我] 认为都是不好的做法”的意思。我在这里只是说我认为
q(...)是不好的做法,因为它很容易与子程序调用混淆。你在测试代码的 sn-ps 时经常做的事情在这里无关紧要,无论如何,如果你计算括号,我认为perl -E '... say join("\n", split("", "foo ". q/$foo/)) ...'更简单。所有这些“重要原因”是什么? -
“我什至更喜欢没有任何单引号的 sn-ps” 然后使用斜杠。但请不要模拟函数调用:即使空格在
q( a b )中也很重要。我们仍在讨论我的意见。
标签: perl eval lexical-scope