2010-02-02 132 views
4

我有一組在Perl聲明的常量的:如何訪問名稱包含在變量中的Perl常量?

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

如何構建,一個Perl表達式,其基於$which_constant,得出與此變量的值命名爲恆定值 - 例如「222」。

請注意,我不能改變上述任何條件 - 它們是一個真實場景的簡化:我有一個模塊(我無法控制)從中導入這些常量。其中一個常量的名稱由用戶從命令行提供。我需要訪問適當的常量值。

我一直在毆打我的頭靠在牆上(主要是圍繞各種奇怪的glob結構),但沒有一個能夠工作。

P.S.如果解決方案訪問其本地模塊內的常量 - 例如My::Constants::C2(無需導入它們),甚至更好,但不是必需的 - 我可以使用My::Constants->import($which_constant)輕鬆地將正確的常量導入main::。是的,爲了實現它,常量不會默認導出,因此需要顯式import()調用。

一些我嘗試過的事情:

  • main::$which_constant - 語法錯誤

  • main::${which_constant} - 語法錯誤

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

  • *$which_constant - 返回「 * main :: C2「

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

+1

如果你有機會改變這一模塊,http://search.cpan.org/perldoc?Readonly或http://search.cpan.org/perldoc?Attribute::Constant似乎爲此使用更適合。 – ephemient 2010-02-02 22:01:02

+1

軟件工程團隊正在控制模塊(對我來說更精確,是自動生成的包含常量列表的數據庫後端)。他們沒有帶寬容量來打擾這種微小/瑣碎的事情,並且不會讓團隊以外的人混淆他們的代碼,而沒有主要業務需要證明變更風險的合理性。他們是在大型金融機構工作時的休息時間。 – DVK 2010-02-03 18:29:29

回答

13

常量只是子程序。您可以使用方法調用的語法,如果你在一個字符串有固定的名稱:

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

這樣一來,如果您嘗試使用不定義一個常數,你會得到一個錯誤。

+0

You'da !男人思南 – DVK 2010-02-02 21:09:49

+0

這是公認的答案一個可能的候選人,除非有人想出一些甚至是狡猾的(不可能的,但,這是Perl中我們所談論的:)) – DVK 2010-02-02 21:10:40

+0

@DVK謝謝;-) – 2010-02-02 21:12:11

8

Perl的 「常量」 實際上是返回一個恆定值的子程序。 perl編譯器能夠在編譯時用適當的值替換它們。不過,既然你想根據運行名稱查找值,你應該做的:

&{$which_constant}(); 

(當然,你需要no strict 'refs'地方。)通過constant.pm定義

+5

或'$ which_constant - >()'或者只是'&$ which_constant' – mob 2010-02-02 21:21:47

+0

花括號是不必要的。 '&$ which_constant()'工作,如果你想跳過魔術'@ _',處理'&$ which_constant'(不是那麼重要)。 – ephemient 2010-02-02 22:06:42

+0

JS - +1提醒我有關「常量只是子程序」,它跳過了我的思路(你的回答是在思南之前,所以即使他的解決方案更符合我的喜好並因此被「接受」也是當之無愧的。 – DVK 2010-02-03 18:31:37

4

思南建議使用方法調用語義來避開strict 'refs'限制是最簡潔,最容易閱讀的解決方案。

我唯一擔心的是使用這種方法的速度懲罰可能是一個問題。我們都聽說過方法調用性能懲罰和可嵌入函數的速度優勢。

所以我決定運行一個基準(代碼和結果如下)。

結果表明,正常,內聯常量運行約快兩倍,法文字子程序名字叫,幾乎三次一樣快,方法與變量的子程序調用的名稱。最慢的方法是標準deref並調用no strict "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; 
} 

而且結果:在Windows XP中,情況因人而異與826的activeperl產生

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

結果。

+0

對於我目前的任務是一個無關緊要的問題(一次性配置調用),但總的來說,這是一個值得關注的問題。我已經在Perl項目中實現了主要的減速,通過重新設計來解決這個問題。 – DVK 2010-02-03 20:02:53

相關問題