【问题标题】:dynamic call to subroutines in perlperl中对子程序的动态调用
【发布时间】:2011-11-22 07:23:14
【问题描述】:

我有点搞砸了以下内容:

我有一个函数以下列方式调用子例程:

sub someFunction {
    my $self = shift;
    my $type = $self->{'type'};

    if($type eq 'one_subroutine') {
        $self->updateOneSubroutine();
    }
    elsif($type eq 'another_one_sub') {
        $self->updateAnotherOneSub();
    }
(...)
    else {
        die "Unsupported '$type'";
    }

我必须改变它,让每个子例程都编码在自己的文件中,包括所有可用的文件,并自动调用里面的子例程。

我在测试文件中使用以下代码执行此操作:

# Assume a routines subdir with one_subroutine.pm file with 
sub updateOneSubroutine(){
    $self = shift;
    $self->doSomeThings();

    (...) #my code
}
1;

test.pl

# Saves in routines hash_ref a pair of file_name => subRoutineName for each file in routines subdir.
# This will be used later to call subroutine.
opendir(DIR,"lib/routines") or die "routines directory not found";
for my $filename (readdir(DIR)) {
    if($filename=~m/\.pm$/){
        # includes file
        require "lib/routines/$filename";
        # get rid of file extension
        $filename=~s/(.*)\.pm/$1/g;
        my $subroutine = "update_${file}";
        # camelizes the subroutine name
        $subroutine=~s/_([a-z0-9])/\u$1/g;
        $routine->{ $filename }  = $subroutine;
    }
}

{
    no strict "refs";
    $routine->{$param}();
}

其中 param 类似于“one_subroutine”,与可用的文件名匹配。

由于每个子程序在调用中都会收到$self,所以我应该通过$self->something();来调用程序

我已经尝试过 $self->$routine->{$param}() 、 $self->${routine->${param}}() 和许多其他方法,但都没有成功。我检查了chapter 9 "dynamic subroutines" of mastering perla similar question to perl monks,但我仍然无法弄清楚如何以代表 $self->updateAnotherOneSub() 的方式引用子例程,或者类似的方式让 $self 被读取为这些子程序中的参数。

提前致谢,凯伯。

【问题讨论】:

  • 为什么sub updateOneSubroutine () { ... 中的原型是空的?如果这不是一个错字,那么它就是一个错误。

标签: perl dynamic this subroutine


【解决方案1】:

这看起来有点像 X/Y 问题。你到底想做什么?如果是为了减少加载时间,您可能会对 AutoSplit/AutoLoader 等模块感兴趣。

如果要创建子程序的某种数据结构,您应该将匿名子程序安装到散列中,而不是给它们全名。

给定一个子程序引用:

my $code = sub {...};

你可以这样称呼它:

$self->$code(...);

如果您有子例程名称,则可以查找 coderef:

my $code = 'Package::With::The::Subroutines'->can('method_name');

如果成功(检查它),那么您可以使用$self->$code(...) 调用它。


鉴于此代码:

{
    no strict "refs";
    $routine->{$param}();
}

您可以将$self 传递给例程:

{
    no strict "refs";
    $routine->{$param}($self);
}

或者你可以按照我上面can的方式来处理它:

'package'->can($routine->{$param})->($self)

如果你不想关闭strict 'refs'

【讨论】:

  • 感谢您对我问题的理解;我已经成功使用了您建议的 coderef 方法,谢谢。
【解决方案2】:

尝试先提取方法名称,然后它应该可以工作。我做了一个小测试脚本,可能会做你想做的事情,所以:

my $method = $routine->{$param};
$self->$method->();

您可以并且当然应该检查是否存在所需的方法,如 Eric 所说:

if ($self->can($method)) {
    $self->$method->();
}

这里的重要部分是,您提取方法名称,以便将其放在单个变量中;否则 perl 不会为你解决这个问题 - 据我所知,没有办法设置括号或大括号。

【讨论】:

    猜你喜欢
    • 2019-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-06
    • 1970-01-01
    • 1970-01-01
    • 2015-12-17
    • 2013-10-30
    相关资源
    最近更新 更多