Perl 中动态调用子例程

发布于 2024-12-17 08:14:46 字数 1889 浏览 0 评论 0原文

我对以下内容有点困惑:

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

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}();
}

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

由于每个子例程在调用中都会接收 $​​self ,因此我应该通过 $self->something(); 来调用该例程。

我尝试过 $self->$routine->{$param}() 、 $self->${routine->${param}}() 和许多其他方法但没有成功。我已经检查了掌握perl的第9章“动态子例程” ,以及 与 perl 类似的问题僧侣,但我仍然无法弄清楚如何以表示 $self->updateAnotherOneSub() 的方式引用子例程,或者类似的方式让 $self 在这些子例程中被读取为参数。

预先感谢,凯伯。

I'm a bit messed up with the following:

I have a function that calls subroutines in the following way:

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'";
    }

I have to change this to let each subroutine be coded in its own file, include all available files, and automagically call the subroutine inside.

I did this in a test file with the following code:

# 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}();
}

where param is something like "one_subroutine", that matches with a filename available.

Since each subroutine receives $self in the call, I should call the routine by $self->something();

I've tried $self->$routine->{$param}() , $self->${routine->${param}}() and many other things without success. I've checked chapter 9 "dynamic subroutines" of mastering perl, and a similar question to perl monks, but I can't still figure out how to reference the subroutine in a way that represents $self->updateAnotherOneSub() , or something similar that lets $self be read as a param in those subroutines.

Thanks in advance, Keber.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

眼眸里的那抹悲凉 2024-12-24 08:14:46

这看起来有点像 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)

如果您不想关闭严格的“参考”

This seems a bit like an X/Y problem. What exactly are you trying to do? If it is to reduce loading time, then modules like AutoSplit/AutoLoader might be of interest to you.

If it is to create some sort of data structure of subroutines, you should be installing anonymous subs into a hash, rather than giving them all names.

Given a subroutine reference:

my $code = sub {...};

you would call it as:

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

If instead you have a subroutine name, you can lookup the coderef:

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

and if that succeeds (check it), then you can use $self->$code(...) to call it.


Given this code:

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

You would pass $self to the routine with:

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

Or you could approach it the way I did above with can:

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

if you don't want to turn off strict 'refs'

維他命╮ 2024-12-24 08:14:46

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

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

你可以而且当然应该检查,是否存在所需的方法,就像埃里克所说:

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

这里重要的部分是,你提取方法名称,这样你就拥有了它在单个变量中;否则 Perl 不会为你解决这个问题 - 据我所知,没有办法设置括号或大括号来做到这一点。

Try to extract the method name first, then it should work. I did a small test script that may do something like you want to, so:

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

You can and of course should check, if the desired method exists like Eric said:

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

The important part here is, that you extract the method name so you have it in a single variable; otherwise perl won't figure that out for you - and as far as I know there is no way of setting parens or braces to do so.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文