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

时间:2017-02-06 09:28:03

标签: perl constants

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

ABC = DEF
GHI = JKL

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

$VAR1 = {
    'ABC' => 'DEF',
    'GHI' => 'JKL'
};

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

的事情
use constant ABC => 'DEF';
use constant GHI => 'JKL';

我尝试过这样做:

foreach my $const (keys %$hashref) {
    use constant $const => $keys->{$const};
}

但正如预期的那样无效。有没有办法实现我想要做的事情?

2 个答案:

答案 0 :(得分: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
   }
);

结果:

               Rate     hash   scalar constant
hash      9427736/s       --      -7%     -10%
scalar   10143017/s       8%       --      -3%
constant 10492078/s      11%       3%       --

所以你是对的 - 使用常数会更快。但是,我建议以10M /秒的速度运行,然后保存' 5%(甚至10%)根本不值得你需要做的hackery。

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

定义constant时,根本没有哈希存在,因此无法正常工作。您在BEGIN区块中实际执行的操作也非常有限。我的想法是你可能可能运行一个'编译'将配置文件转换为.pm然后use的过程。

package import_const;

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

然后use import_const;并以import_const::ABC的形式访问您的常量。 (或使用Exporter将它们带入本地命名空间)。

sub from_pkg { 
    my $value  = import_const::ABC;
    my $value2 = import_const::GHI;
}

将其添加到计时测试中:

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

我认为我仍然认为努力的收益微不足道。特别是use constant will surprise you with it's evil

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

CPAN modules for defining constants

答案 1 :(得分:4)

首先,你可以做到

use constant {
   CONST1 => VAL1,
   CONST2 => VAL2,
   ...
};
use constant LIST

相当于

BEGIN {
   require constant;
   constant->import(LIST);
}

use constant qw( );
BEGIN {
   constant->import(LIST);
}

所以你可以做到

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

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

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;

use FindBin qw( $RealBin );
use MyConstantsFromFile "$RealBin/constants.json";