我已经完成了搜索,但无法找到答案。如果在其他地方得到回答,请道歉。
我有一组这样的常量:
use constant {
STATS_AXLE_SPOT_OK => 0,
STATS_AXLE_SPOT_ERROR => 1,
STATS_AXLE_SPOT_SKIPPED => 2,
STATS_AXLE_FORWARD_OK => 3,
STATS_AXLE_FORWARD_ERROR => 4,
STATS_AXLE_FORWARD_SKIPPED => 5,
}
我想做的是有一个函数,我可以构造常量的名称并使用常量的值。
例如
sub DoStuff()
{
my $l_deal_type = $_[0];
my $l_status = $_[1];
#code from here isn't correct.
my $l_constant_name = "STATS_AXLE_" . $l_deal_type . "_" . $l_status;
print $l_constant_name;
}
#prints value of constant STATS_AXLE_SPOT_SKIPPED
DoStuff("SPOT", "SKIPPED");
感谢您的帮助!
答案 0 :(得分:3)
简要总结:首先,不要使用字符串eval
。它会损害性能,并且可能会掩盖代码的问题。
其次,主要问题是为什么你需要这样做。如果你需要一个键值查找工具,Perl已经有了一个数据结构,你应该使用它。
如果您只需要在一个地方执行此操作,则可以通过构造其名称来调用使用use constant
语句创建的常量作为函数。这就是Hynek -Pichi- Vychodil's answer正在做的事情。
如果您需要在代码中的多个位置执行此操作,最好调整查找,以便您的代码不会出现no strict 'refs'
。这就是pilcrow's answer给你的东西。检查常量子例程的定义是否会影响性能,但如果您希望异常告诉您代码的哪一部分试图查找不存在的值,则必须这样做。
对我而言,Const::Fast似乎更适合您的情况。它允许您在不是包命名空间的单个命名空间中收集相关常量,使用简单的Perl结构查找和插入这些常量等。
use Const::Fast;
const my %STATS_AXLE => (
SPOT_OK => 0,
SPOT_ERROR => 1,
SPOT_SKIPPED => 2,
FORWARD_OK => 3,
FORWARD_ERROR => 4,
FORWARD_SKIPPED => 5,
);
然后你可以say $STATS_AXLE{SPOT_ERROR}
或
say $STATS_AXLE{ "${l_deal_type}_${l_status}" };
或
say $STATS_AXLE{ "$_[0]_$_[1]" };
是您的DoStuff
例程。
如果%STATS_AXLE
中不存在该密钥,则此 将会突然显示。
要对CPAN modules for defining constants进行精彩比较,请参阅Neil Bowers' excellent review。我同意他的建议是:
如果需要数组或散列常量或不可变的富数据结构,请使用Const::Fast。这与Attribute::Constant之间的竞争非常激烈,但
Const::Fast
似乎更成熟,而且还有更多 版本。
PS:请注意sub DoStuff()
声明DoStuff
不接受任何参数。只是不要使用Perl的原型。他们没有做大多数人期望他们做的事情。做:
sub DoStuff {
....
}
答案 1 :(得分:2)
Perl的constant
有效地定义了子程序,你可以在符号表中检查某个名称的子程序的存在......象征性地:
use strict;
use Carp qw(croak);
....
sub lookup_const {
my $name = shift;
croak "No such constant '$name'" unless defined &$name; # this works even under strict
no strict 'refs';
return &{$name}; # this won't work under strict
}
修改强>
但是,您可能不想这样做。
典型的,简单的标量constant
(例如,use constant FLAG_FOO => 1
)非常适合定义无限子程序的非常有限的应用程序,这些子程序为开发人员提供了一个有意义的名称,否则"魔术&# 34;文字。这与您可能熟悉的另一种语言中的#define FLAG_FOO 1
没有什么不同。
当你超越这个简单的用法时,constant
的实现将很快发生。按名称的动态常量查找会破坏常量subs的内联。插值"常数"使用只读(按惯例或其他方式)变量更容易。等
答案 2 :(得分:1)
如果你看constant.pm
,你会发现常量只是一个模块,它安装一个函数,将常量值返回到当前命名空间。它在编译时完成,然后Perl在下面的代码中将其优化为常量。关键是仍然有功能,所以你可以调用它。
sub DoStuff
{
my $l_deal_type = $_[0];
my $l_status = $_[1];
my $l_constant_name = "STATS_AXLE_${l_deal_type}_${l_status}";
no strict 'refs';
print $l_constant_name->();
}
如果你绝望,可以将constant与Const::Fast结合起来并制作这些奇怪的内容:
use strict;
use warnings;
use Const::Fast;
const my %STATS_AXLE => (
SPOT_OK => 0,
SPOT_ERROR => 1,
SPOT_SKIPPED => 2,
FORWARD_OK => 3,
FORWARD_ERROR => 4,
FORWARD_SKIPPED => 5,
);
use constant STATS_AXLE => \%STATS_AXLE;
use v5.10;
for my $type (qw(SPOT FORWARD)) {
for my $status (qw(OK ERROR SKIPPED)) {
say "1st way STATS_AXLE_${type}_$status => ", $STATS_AXLE{"${type}_$status"};
say "2nd way STATS_AXLE_${type}_$status => ", STATS_AXLE->{"${type}_$status"};
}
}
# this works as well
say $STATS_AXLE{FORWARD_ERROR};
say STATS_AXLE->{FORWARD_ERROR};