[英]How can I elegantly call a Perl subroutine whose name is held in a variable?
我保留了我想在運行時在名為$ action的變量中調用的子例程的名稱。 然后我用它在正確的時間調用該子:
&{\&{$action}}();
工作良好。 我唯一不喜歡的是它很丑陋,每次我這樣做,我都感到很高興為下一個開發者添加評論:
# call the sub by the name of $action
有人知道更漂亮的方式嗎?
更新:這里的想法是避免每次添加新的可調用子時都必須維護一個調度表,因為我是唯一的開發人員,我不擔心其他程序員遵循或不遵循“規則”。 為了方便我犧牲了一點安全性。 相反,我的調度模塊將檢查$ action以確保1)它是已定義的子例程的名稱而不是與eval一起運行的惡意代碼,以及2)它不會運行任何以下划線開頭的子,這將是通過此命名約定標記為僅限內部的subs。
有關這種方法的任何想法? 發送表中的白名單子程序是我一直都會忘記的東西,我的客戶寧願我在“它工作”而不是“它是邪惡的安全”方面犯錯誤。 (開發應用程序的時間非常有限)
最后更新:我想我畢竟已經決定了一個調度表。 雖然我很好奇,如果讀過這個問題的人曾經試圖廢除一個以及他們是如何做到的,那么我不得不向這里的集體智慧屈服。 感謝所有,許多偉大的回應。
不是將子例程名稱存儲在變量中並調用它們,更好的方法是使用子例程引用的哈希(也稱為分派表) 。
my %actions = ( foo => \&foo,
bar => \&bar,
baz => sub { print 'baz!' }
...
);
然后你可以輕松地撥打正確的電話:
$actions{$action}->();
您還可以添加一些檢查以確保$action
是哈希中的有效鍵,依此類推。
一般來說,你應該避免使用符號引用(你現在正在做什么),因為它們會導致各種各樣的問題。 此外,使用實際子例程引用將strict
打開。
只是&$action()
,但通常從一開始就使用coderefs更好,或使用調度程序哈希。 例如:
my $disp = {foo => \&some_sub, bar => \&some_other_sub };
$disp->{'foo'}->();
咦? 你可以說
$action->()
例:
sub f { return 11 }
$action = 'f';
print $action->();
$ perl subfromscalar.pl
11
像。這樣的結構
'f'->() # equivalent to &f()
也工作。
我不確定我明白你的意思。 (我認為這是最近一組“如何使用變量作為變量名?”的問題,但可能沒有。)
在任何情況下,您都應該能夠將整個子例程分配給變量(作為參考),然后直接調用它:
# create the $action variable - a reference to the subroutine
my $action = \&preach_it;
# later - perhaps much later - I call it
$action->();
sub preach_it {
print "Can I get an amen!\n"
}
最重要的是:為什么要將變量用作函數名。 如果它是'eval'會發生什么? 是否有可以使用的功能列表? 或者它可以是任何功能? 如果列表存在 - 它有多長?
通常,處理此類情況的最佳方法是使用調度表:
my %dispatch = (
'addition' => \&some_addition_function,
'multiplication' => sub { $self->call_method( @_ ) },
);
然后就是:
$dispatch{ $your_variable }->( 'any', 'args' );
__PACKAGE__->can($action)->(@args);
有關can()的更多信息: http : //perldoc.perl.org/UNIVERSAL.html
我做了類似的事情。 我把它分成兩行,使它更容易識別,但它並不是很漂亮。
my $sub = \&{$action};
$sub->();
我不知道更正確或更漂亮的方式。 對於它的價值,我們有生產代碼可以完成您正在做的事情,並且無需禁用use strict
。
Perl中的每個包都已經是一個哈希表。 您可以通過常規哈希操作添加元素並引用它們。 通常,沒有必要通過附加的哈希表來復制功能。
#! /usr/bin/perl -T
use strict;
use warnings;
my $tag = 'HTML';
*::->{$tag} = sub { print '<html>', @_, '</html>', "\n" };
HTML("body1");
*::->{$tag}("body2");
代碼打印:
<html>body1</html> <html>body2</html>
如果需要單獨的名稱空間,則可以定義專用包。
有關詳細信息,請參閱perlmod 。
要么使用
&{\&{$action}}();
或者使用eval執行該功能:
eval("$action()");
我是這樣做的:
@func = qw(cpu mem net disk);
foreach my $item (@func){
$ret .= &$item(1);
}
如果只在一個程序中,編寫一個使用變量名稱調用子程序的函數,只需記錄一次/道歉一次?
我用過這個:它對我有用。
(\$action)->();
或者您可以使用'do',與以前的帖子非常相似:
$p = do { \&$conn;};
$p->();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.