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

发布于 2024-08-20 13:08:46 字数 940 浏览 3 评论 0原文

我在 Perl 中声明了一组常量:

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

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

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

我一直在用头撞墙(主要是围绕各种奇怪的全局结构),但它们都不起作用。

PS 如果解决方案访问其本机模块内的常量 - 比如 My::Constants::C2 (无需导入它们),那就更好,但不是必需的 - 我可以将正确的常量导入到 < code>main:: 轻松使用 My::Constants->import($which_constant)。是的,最重要的是,默认情况下不会导出常量,因此需要显式 import() 调用。

我尝试过的一些事情:

  • main::$which_constant - 语法错误

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

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

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

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

I have a set of constants declared in Perl:

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

How do I construct a Perl expression which, based on $which_constant, derives the value of a constant named with the value of this variable - e.g. "222".

Please note that I can not change any of the conditions above - they are a simplification of a real scenario: I have a module (which I have no control over) from which these constants are imported. The `name of one of the constants is supplied by the user from command line. I need to access the appropriate constants' value.

I've been beating my head against the wall (mostly around all sorts of weird glob constructs) but none of them work.

P.S. If the solution accesses the constants inside their native module - say My::Constants::C2 (without needing to import them), even better, but not necessary - I can import the correct constants into main:: easily using My::Constants->import($which_constant). and yes, to top it off, te constants are NOT exported by default thus needing the explicit import() call.

Some of the things I tried:

  • main::$which_constant - syntax error

  • main::${which_constant} - syntax error

  • ${*$which_constant} - returns empty value

  • *$which_constant - returns "*main::C2"

  • ${*${*which_constant}} - empty

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一江春梦 2024-08-27 13:08:46

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 );

这样,如果您尝试使用未定义的常量,您将收到错误。

Constants defined by constant.pm are just subroutines. You can use method invocation syntax if you have the name of the constant in a string:

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

This way, if you try to use a constant which is not defined, you will get an error.

善良天后 2024-08-27 13:08:46

Perl“常量”实际上是返回常量值的子例程。 Perl 编译器能够在编译时将它们替换为适当的值。但是,由于您希望根据运行时名称查找来获取值,因此您应该这样做:(

&{$which_constant}();

当然,您需要在某处没有严格的“refs”。)

Perl "constants" are actually subroutines that return a constant value. The perl compiler is able to replace them with the appropriate value at compile time. However, since you want to get the value based on a runtime name lookup, you should do:

&{$which_constant}();

(And of course you need no strict 'refs' somewhere.)

是你 2024-08-27 13:08:46

Sinan 建议使用方法调用语义来绕过严格的“refs”限制,这是最干净、最容易阅读的解决方案。

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

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

结果表明,正常的内联常量的运行速度大约是使用字面子例程名称的方法调用的两倍,几乎是使用变量子例程名称的方法调用的三倍。最慢的方法是标准解引用和调用无严格“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 上使用 ActivePerl 826 生成的结果,YMMV。

Sinan's suggestion to use method invocation semantics to get around strict 'refs' limits is the cleanest, easiest to read solution.

My only concern about this was that the speed penalty for using this approach might be a problem. We've all heard about method call performance penalties and the speed benefits of inlineable functions.

So I decided to run a benchmark (code and results follow).

The results show that normal, inlined constants run about twice as fast as method calls with a literal subroutine name, and almost three times as fast as method calls with variable subroutine names. The slowest approach is a standard deref and invocation of no strict "refs";.

But, even the slowest approach is pretty darn fast at over 1.4 million times a second on my system.

These benchmarks obliterate my one reservation about using the method call approach to solve this problem.

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;
}

And the results:

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

Results generated with ActivePerl 826 on Windows XP, YMMV.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文