名前が変数に含まれている Perl の定数にアクセスするにはどうすればよいですか?
-
25-09-2019 - |
質問
Perl で宣言された定数のセットがあります。
use constant C1 => 111;
use constant C2 => 222;
..
use constant C9 => 999;
my $which_constant = "C2";
に基づいて Perl 式を構築するにはどうすればよいですか? $which_constant
, 、この変数の値で名前が付けられた定数の値を導出します。「222」。
上記の条件はいずれも変更できないことに注意してください。これらは実際のシナリオを簡略化したものです。これらの定数をインポートするモジュール (制御できません) があります。定数の 1 つの名前は、ユーザーがコマンドラインから指定します。適切な定数の値にアクセスする必要があります。
私は壁に頭をぶつけてきましたが(ほとんどの場合、あらゆる種類の奇妙なグロブ構造の周りで)、どれも機能しません。
追伸ソリューションがネイティブ モジュール内の定数にアクセスする場合 - たとえば、 My::Constants::C2
(それらをインポートする必要はありません)さらに良いですが、必須ではありません - 正しい定数をインポートできます main::
簡単に使用 My::Constants->import($which_constant)
. 。はい、おまけに、定数はデフォルトではエクスポートされないため、明示的な import() 呼び出しが必要です。
私が試したことのいくつか:
main::$which_constant
- 構文エラーmain::${which_constant}
- 構文エラー${*$which_constant}
- 空の値を返します*$which_constant
- 「*main::C2」を返します${*${*which_constant}}
- 空の
解決
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'
どこかにする必要があります。)
strict 'refs'
制限を周りに取得するメソッド呼び出しのセマンティクスを使用するには、シナンの提案は、ソリューションを読むことが最も簡単なクリーンです。
このについての私の唯一の懸念は、このアプローチを使用するための速度ペナルティが問題になるかもしれないということでした。我々は、すべてのメソッド呼び出しのパフォーマンスの低下やinlineable機能の速度の利点について聞きました。
だから私は、ベンチマーク(コードと結果に従う)を実行することを決定します。
の結果は通常、インライン化定数リテラルサブルーチン名を持つメソッド呼び出しと同じ速さ約二倍実行することを示し、ほぼ3倍の速変数サブルーチン名を持つメソッド呼び出しとして。最も遅いのアプローチは、標準的な被参照とno strict "refs";
の呼び出しです。
しかし、でも、最も遅いのアプローチは、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で生成された結果。