4

Perl で宣言された一連の定数があります。

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

$which_constantに基づいて、この変数の値で名前が付けられた定数の値を導出する Perl 式を作成するにはどうすればよいですか。たとえば、「222」です。

上記の条件のいずれも変更できないことに注意してください。これらは実際のシナリオを単純化したものです。これらの定数をインポートするモジュール (制御できない) があります。定数の 1 つの名前は、ユーザーがコマンド ラインから指定します。適切な定数の値にアクセスする必要があります。

私は壁に頭をぶつけてきましたが(ほとんどはあらゆる種類の奇妙なグロブ構造の周りにあります)、どれも機能しません。

PSソリューションがネイティブモジュール内の定数にアクセスする場合-たとえばMy::Constants::C2(それらをインポートする必要なしに)、さらに良いが、必須ではありません-正しい定数をmain::簡単に使用してインポートできMy::Constants->import($which_constant)ます. さらに、定数はデフォルトではエクスポートされないため、明示的な import() 呼び出しが必要です。

私が試したことのいくつか:

  • main::$which_constant - 構文エラー

  • main::${which_constant} - 構文エラー

  • ${*$which_constant}- 空の値を返します

  • *$which_constant- "*main::C2" を返します

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

4

3 に答える 3

13

で定義された定数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 );

このように、定義されていない定数を使用しようとすると、エラーが発生します。

于 2010-02-02T21:07:44.387 に答える
8

Perl の「定数」は、実際には定数値を返すサブルーチンです。perl コンパイラは、コンパイル時にそれらを適切な値に置き換えることができます。ただし、ランタイム名のルックアップに基づいて値を取得する必要があるため、次のようにする必要があります。

&{$which_constant}();

(そしてもちろん、no strict 'refs'どこかが必要です。)

于 2010-02-02T21:07:36.957 に答える
4

メソッド呼び出しのセマンティクスを使用してstrict 'refs'制限を回避するという Sinan の提案は、最もクリーンで読みやすいソリューションです。

これに関する私の唯一の懸念は、このアプローチを使用することによる速度のペナルティが問題になる可能性があることでした. メソッド呼び出しのパフォーマンスの低下と、インライン化可能な関数の速度の利点については、誰もが聞いたことがあるでしょう。

そこで、ベンチマークを実行することにしました (コードと結果が続きます)。

結果は、通常のインライン定数は、リテラル サブルーチン名を使用したメソッド呼び出しの約 2 倍の速度で実行され、変数サブルーチン名を使用したメソッド呼び出しのほぼ 3 倍の速度で実行されることを示しています。最も遅いアプローチは、標準の deref と の呼び出しですno strict "refs";

しかし、最も遅いアプローチでさえ、私のシステムでは 1 秒間に 140 万回以上と非常に高速です。

これらのベンチマークは、この問題を解決するためにメソッド呼び出しアプローチを使用することに関する私の 1 つの留保を消し去ります。

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 を使用して生成された結果。

于 2010-02-03T19:14:23.587 に答える