繁体   English   中英

如何在Perl中访问名称包含在变量中的常量?

[英]How do I access a constant in Perl whose name is contained in a variable?

我有一组在Perl中声明的常量:

   use constant C1 => 111;
   use constant C2 => 222;
   ..
   use constant C9 => 999;
   my $which_constant = "C2";

如何构造一个Perl表达式,它基于$which_constant ,派生一个以该变量的值命名的常量的值 - 例如“222”。

请注意,我无法更改上述任何条件 - 它们是真实场景的简化:我有一个模块(我无法控制)从中导入这些常量。 其中一个常量的名称由用户从命令行提供。 我需要访问适当的常量值。

我一直在靠墙撞击(主要围绕各种怪异的glob构造),但它们都不起作用。

PS如果解决方案访问其原生模块中的常量 - 比如My::Constants::C2 (无需导入它们),甚至更好,但不是必需的 - 我可以使用My::Constants->import($which_constant) easy将正确的常量导入main:: My::Constants->import($which_constant) 是的,最重要的是,默认情况下不会导出te常量,因此需要显式的import()调用。

我试过的一些事情:

  • main::$which_constant - 语法错误

  • main::${which_constant} - 语法错误

  • ${*$which_constant} - 返回空值

  • *$which_constant - 返回“* main :: C2”

  • ${*${*which_constant}} - 空

constant.pm定义的constant.pm只是子程序。 如果在字符串中包含常量的名称,则可以使用方法调用语法:

#!/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' 。)

Sinan建议使用方法调用语义来绕过strict 'refs'限制是最干净,最容易阅读的解决方案。

我唯一担心的是使用这种方法的速度惩罚可能是一个问题。 我们都听说过方法调用性能惩罚和内联函数的速度优势。

所以我决定运行一个基准测试(代码和结果如下)。

结果表明,正常的内联常量运行速度大约是使用文字子程序名称的方法调用的两倍,几乎是具有可变子程序名称的方法调用的三倍。 最慢的方法是标准deref和no strict "refs";调用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;
}

结果如下:

                 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%     --

在Windows XP,YMMV上使用ActivePerl 826生成的结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM