`eval { $constant_name }` 给出名称,而不是值

`eval { $constant_name }` gives the name, not the value

我已经定义了几个 Perl 常量,例如 use constant LVL_FATAL => 1; (perl 5.18.2)。 当试图创建一个需要名称和常量值的函数时,我尝试了:

my $level = eval { 'LVL_' . $_ };

$_FATAL时,$level包含LVL_FATAL,但不包含LVL_FATAL的值。

我还尝试了变体 eval { $level }eval { ($level) }eval { my x = $level }eval { print $level }。 他们都用LVL_FATAL.

但是当我使用 eval "$level" 时,我得到 1。 另外,当我使用 eval { LVL_FATAL } 时,我也会得到 1

出于稳健性和性能原因,我可以使用块变体而不是字符串变体吗?

备注

记住 Perl 常量基本上是函数,我尝试了 eval ${level}(),但是没有用; eval { $level->() } 似乎在调试器中完成了这项工作,但是当我在我的程序代码中使用它时,它并没有起作用。

(不使用 eval时,LVL_FATAL->()会报错("Undefined subroutine &main::1 ..."),但LVL_FATAL()是OK的。)

以下似乎有效:

my $level = eval { my $name = "LVL_$_"; __PACKAGE__->$name() };

根据the documentation

Constants belong to the package they are defined in. [...] Constants may be exported by modules, and may also be called as either class or instance methods, that is, as Some::Package->CONSTANT or as $obj->CONSTANT where $obj is an instance of Some::Package. Subclasses may define their own constants to override those in their base class.

eval BLOCKeval EXPR有很大的不同。

eval BLOCK 捕获块中代码抛出的异常。它在其他一些语言中被称为 try

eval EXPR编译并执行EXPR返回的字符串。 (也捕获异常。)

你想要后者。

my $level = eval("LVL_$_");
die $@ if $@;

但是由于常量可以用作子变量,所以您也可以使用

my $level = do { no strict qw( refs );  "LVL_$_"->() };

您也可以将此“子”称为方法。

my $name = "LVL_$_";
my $level = __PACKAGE__->$name();

我更喜欢倒数第二个版本,因为它很明显表明您正在做一些奇怪和危险的事情(并且它不会假装不是方法的 sub 是方法)。