簡體   English   中英

我怎樣才能優雅地調用名稱保存在變量中的Perl子例程?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM