使用变量名定义Perl中的常量

Vin*_*nce 1 perl constants

我想从配置文件中创建perl-constants.我正在使用Config :: File来读取如下所示的配置文件:

ABC = DEF
GHI = JKL
Run Code Online (Sandbox Code Playgroud)

使用Config :: File创建一个如下所示的hashref:

$VAR1 = {
    'ABC' => 'DEF',
    'GHI' => 'JKL'
};
Run Code Online (Sandbox Code Playgroud)

我想使用hashref来创建常量,其中常量的名称应该是键,值应该是hashref中的对应值.手动我会做类似的事情

use constant ABC => 'DEF';
use constant GHI => 'JKL';
Run Code Online (Sandbox Code Playgroud)

我尝试过这样做:

foreach my $const (keys %$hashref) {
    use constant $const => $keys->{$const};
}
Run Code Online (Sandbox Code Playgroud)

但正如预期的那样不起作用.有没有办法实现我想要做的事情?

Sob*_*que 5

我发布这个作为答案,从评论中提取 - 哈希与常数:

#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
use Benchmark qw(:all);

use constant ABC => 'DEF';
use constant GHI => 'JKL';

my $ABC = 'DEF';
my $GHI = 'JKL';

my %test_hash = (
   ABC => 'DEF',
   GHI => 'JKL'
);

sub access_hash {
   my $value  = $test_hash{ABC};
   my $value2 = $test_hash{DEF};
}

sub access_constant {
   my $value  = ABC;
   my $value2 = GHI;
}

sub access_scalar { 
    my $value = $ABC;
    my $value2 = $GHI;
} 

my $count = 100_000_000;

cmpthese(
   $count,
   {  'hash'     => \&access_hash,
      'constant' => \&access_constant,
      'scalar'   => \&access_scalar
   }
);
Run Code Online (Sandbox Code Playgroud)

结果:

               Rate     hash   scalar constant
hash      9427736/s       --      -7%     -10%
scalar   10143017/s       8%       --      -3%
constant 10492078/s      11%       3%       --
Run Code Online (Sandbox Code Playgroud)

所以你是对的 - 使用常数更快.但是,我建议以10M /秒的速度运行,"节省"5%(甚至10%)根本不值得你需要做的hackery.

但是为了实际回答问题 - 这个问题的根源constant是在编译时定义的,其中变量......不是.

constant定义时,根本没有哈希存在,因此不会起作用.您在BEGIN块中实际可以做的事情也非常有限.我的想法是你可能运行一个'编译'过程来将你的配置文件变成.pm你可以的那个use.

package import_const;

use constant ABC => 'DEF';
use constant GHI => 'JKL';
Run Code Online (Sandbox Code Playgroud)

然后use import_const;访问你的常量import_const::ABC.(或者用Exporter它们将它们带入本地命名空间).

sub from_pkg { 
    my $value  = import_const::ABC;
    my $value2 = import_const::GHI;
}
Run Code Online (Sandbox Code Playgroud)

将其添加到计时测试中:

                        Rate        hash     scalar imported constant   constant
hash               9497578/s          --        -6%               -9%        -9%
scalar            10063399/s          6%         --               -4%        -4%
imported constant 10473398/s         10%         4%                --        -0%
constant          10492078/s         10%         4%                0%         --
Run Code Online (Sandbox Code Playgroud)

我想我仍然认为努力的收益微不足道.特别是使用常数会让你惊讶它的邪恶

可能有一个模块可以做你需要的事情:

用于定义常量的CPAN模块


ike*_*ami 5

首先,你可以做

use constant {
   CONST1 => VAL1,
   CONST2 => VAL2,
   ...
};
Run Code Online (Sandbox Code Playgroud)
use constant LIST
Run Code Online (Sandbox Code Playgroud)

相当于

BEGIN {
   require constant;
   constant->import(LIST);
}
Run Code Online (Sandbox Code Playgroud)

或者

use constant qw( );
BEGIN {
   constant->import(LIST);
}
Run Code Online (Sandbox Code Playgroud)

所以你可以做

use constant qw( );
use FindBin  qw( $RealBin );
use JSON::XS qw( decode_json );

BEGIN {
   my $qfn = "$RealBin/constants.json";
   open(my $fh, '<:raw', $qfn) or die $!;
   my $file; { local $/; $file = <$fh>; }
   my $constants = decode_json($file);  # { 'ABC' => 'DEF', 'GHI' => 'JKL' };
   constant->import($constants);
}
Run Code Online (Sandbox Code Playgroud)

更清洁的解决方案可能是使用迷你模块。

package MyConstantsFromFile;

use strict;
use warnings;

use constant qw( );
use JSON::XS qw( decode_json );

sub import {
   my $class = shift;
   my $qfn = shift;
   open(my $fh, '<:raw', $qfn) or die $!;
   my $file; { local $/; $file = <$fh>; }
   my $constants = decode_json($file);  # { 'ABC' => 'DEF', 'GHI' => 'JKL' };
   my $import = constant->can('import');
   @_ = ('constant', $constants);
   goto &$import;
}

1;
Run Code Online (Sandbox Code Playgroud)

use FindBin qw( $RealBin );
use MyConstantsFromFile "$RealBin/constants.json";
Run Code Online (Sandbox Code Playgroud)