如何访问名称包含在变量中的Perl常量?
我有一组在Perl声明的常量的:如何访问名称包含在变量中的Perl常量?
use constant C1 => 111;
use constant C2 => 222;
..
use constant C9 => 999;
my $which_constant = "C2";
如何构建,一个Perl表达式,其基于$which_constant
,得出与此变量的值命名为恒定值 - 例如“222”。
请注意,我不能改变上述任何条件 - 它们是一个真实场景的简化:我有一个模块(我无法控制)从中导入这些常量。其中一个常量的名称由用户从命令行提供。我需要访问适当的常量值。
我一直在殴打我的头靠在墙上(主要是围绕各种奇怪的glob结构),但没有一个能够工作。
P.S.如果解决方案访问其本地模块内的常量 - 例如My::Constants::C2
(无需导入它们),甚至更好,但不是必需的 - 我可以使用My::Constants->import($which_constant)
轻松地将正确的常量导入main::
。是的,为了实现它,常量不会默认导出,因此需要显式import()调用。
一些我尝试过的事情:
main::$which_constant
- 语法错误main::${which_constant}
- 语法错误${*$which_constant}
- 返回空值*$which_constant
- 返回“ * main :: C2“${*${*which_constant}}
- 空
常量只是子程序。您可以使用方法调用的语法,如果你在一个字符串有固定的名称:
#!/usr/bin/perl -l
use strict; use warnings;
use constant C1 => 111;
use constant C2 => 222;
print __PACKAGE__->$_ for qw(C1 C2);
# or print main->$_ for qw(C1 C2);
这样一来,如果您尝试使用不定义一个常数,你会得到一个错误。
Perl的 “常量” 实际上是返回一个恒定值的子程序。 perl编译器能够在编译时用适当的值替换它们。不过,既然你想根据运行名称查找值,你应该做的:
&{$which_constant}();
(当然,你需要no strict 'refs'
地方。)通过constant.pm
定义
思南建议使用方法调用语义来避开strict 'refs'
限制是最简洁,最容易阅读的解决方案。
我唯一担心的是使用这种方法的速度惩罚可能是一个问题。我们都听说过方法调用性能惩罚和可嵌入函数的速度优势。
所以我决定运行一个基准(代码和结果如下)。
结果表明,正常,内联常量运行约快两倍,法文字子程序名字叫,几乎三次一样快,方法与变量的子程序调用的名称。最慢的方法是标准deref并调用no strict "refs";
。
但是,即使是最慢的方法是在我的系统上第二个超过140万次相当不错的快。
这些基准泯有关使用方法调用的方法来解决这个问题,我的一个保留。
use strict;
use warnings;
use Benchmark qw(cmpthese);
my $class = 'MyConstant';
my $name = 'VALUE';
my $full_name = $class.'::'.$name;
cmpthese(10_000_000, {
'Normal' => \&normal_constant,
'Deref' => \&direct_deref,
'Deref_Amp' => \&direct_deref_with_amp,
'Lit_P_Lit_N' => \&method_lit_pkg_lit_name,
'Lit_P_Var_N' => \&method_lit_pkg_var_name,
'Var_P_Lit_N' => \&method_var_pkg_lit_name,
'Var_P_Var_N' => \&method_var_pkg_var_name,
});
sub method_lit_pkg_lit_name {
return 7 + MyConstant->VALUE;
}
sub method_lit_pkg_var_name {
return 7 + MyConstant->$name;
}
sub method_var_pkg_lit_name {
return 7 + $class->VALUE;
}
sub method_var_pkg_var_name {
return 7 + $class->$name;
}
sub direct_deref {
no strict 'refs';
return 7 + $full_name->();
}
sub direct_deref_with_amp {
no strict 'refs';
return 7 + &$full_name;
}
sub normal_constant {
return 7 + MyConstant::VALUE();
}
BEGIN {
package MyConstant;
use constant VALUE => 32;
}
而且结果:在Windows XP中,情况因人而异与826的activeperl产生
Rate Deref_Amp Deref Var_P_Var_N Lit_P_Var_N Lit_P_Lit_N Var_P_Lit_N Normal
Deref_Amp 1431639/s -- -0% -9% -10% -29% -35% -67%
Deref 1438435/s 0% -- -9% -10% -28% -35% -67%
Var_P_Var_N 1572574/s 10% 9% -- -1% -22% -29% -64%
Lit_P_Var_N 1592103/s 11% 11% 1% -- -21% -28% -63%
Lit_P_Lit_N 2006421/s 40% 39% 28% 26% -- -9% -54%
Var_P_Lit_N 2214349/s 55% 54% 41% 39% 10% -- -49%
Normal 4353505/s 204% 203% 177% 173% 117% 97% --
结果。
对于我目前的任务是一个无关紧要的问题(一次性配置调用),但总的来说,这是一个值得关注的问题。我已经在Perl项目中实现了主要的减速,通过重新设计来解决这个问题。 – DVK 2010-02-03 20:02:53
如果你有机会改变这一模块,http://search.cpan.org/perldoc?Readonly或http://search.cpan.org/perldoc?Attribute::Constant似乎为此使用更适合。 – ephemient 2010-02-02 22:01:02
软件工程团队正在控制模块(对我来说更精确,是自动生成的包含常量列表的数据库后端)。他们没有带宽容量来打扰这种微小/琐碎的事情,并且不会让团队以外的人混淆他们的代码,而没有主要业务需要证明变更风险的合理性。他们是在大型金融机构工作时的休息时间。 – DVK 2010-02-03 18:29:29