简体   繁体   English

如何在数组引用中使用索引作为Perl中的方法引用?

[英]How do I use an index in an array reference as a method reference in Perl?

Similar to this question about iterating over subroutine references , and as a result of answering this question about a OO dispatch table , I was wondering how to call a method reference inside a reference, without removing it first, or if it was even possible. 类似于关于迭代子例程引用的问题 ,并且作为回答关于OO调度表的这个问题的结果,我想知道如何在引用中调用方法引用,而不是先删除它,或者甚至是否可能。

For example: 例如:

package Class::Foo;
use 5.012;   #Yay autostrict!
use warnings;

# a basic constructor for illustration purposes....
sub new { 
    my $class = shift;
    return bless {@_}, $class;
}

# some subroutines for flavor...
sub sub1 { say 'in sub 1'; return shift->{a} }
sub sub2 { say 'in sub 2'; return shift->{b} }
sub sub3 { say 'in sub 3'; return shift->{c} }

# and a way to dynamically load the tests we're running...
sub sublist {
    my $self = shift; 
    return [
        $self->can('sub1'),
        $self->can('sub3'),
        $self->can('sub2'),
    ];
}

package main;

sub get_index { ... } # details of how we get the index not important    

my $instance = Class::Foo->new(a => 1, b => 2, c => 3);
my $subs = $instance->sublist();
my $index = get_index();

# <-- HERE

So, at HERE, we could do: 那么,在HERE,我们可以做到:

my $ref = $subs->[$index];
$instance->$ref();

but how would we do this, without removing the reference first? 但是如果不首先删除引用,我们将如何做到这一点呢?

Edit: 编辑:

Changed code example so people don't get hung up on implementation details (sigh, tried my best). 更改了代码示例,以便人们不会对实现细节感到困惑(叹息,尽我所能)。 The important difference between this and the first link I gave was that the function should be invoked as a method , not as a straight subroutine. 这与我给出的第一个链接之间的重要区别在于, 函数应该作为方法调用 ,而不是作为直接子例程调用。

Edit 2: 编辑2:

See the discussion in the linked comment about the technical details, and why the longer way (storing the subref to a variable, then calling it) is probably preferable. 请参阅关于技术细节的链接注释中讨论 ,以及为什么更长的方式(将subref存储到变量,然后调用它)可能更可取。

As written, you can get away with 如上所述,你可以逃脱

$tests->[$index]();

because the methods in your question aren't using $self . 因为你问题中的方法不是使用$self

You could pass $instance explicitly, but that's clunky. 你可以明确地传递$instance ,但这很笨重。 Better would be to simulate delegates with closures: 更好的是模拟具有闭包的代理:

sub sublist {
    my $self = shift;
    my $sublist;
    for (qw/ sub1 sub3 sub2 /) {
      my $meth = $_;
      push @$sublist => sub { $self->$meth() };
    }
    return $sublist;
}

If you prefer to be concise, use 如果您想简洁,请使用

sub sublist {
    my $self = shift;
    return [ map { my $meth = $_; sub { $self->$meth() } }
             qw/ sub1 sub3 sub2 / ];
}

Calling one at random is still 随机拨打一个仍然是

$tests->[$index]();

but now the methods get invocants. 但现在方法得到了调用。


Update 更新

Grabbing subrefs via can appears to be unnecessary complexity. 通过can抓取subrefs似乎是不必要的复杂性。 If a runtime-determined list of names of methods to call will do, then you can simplify your code greatly: 如果运行时确定要调用的方法名称列表,则可以大大简化代码:

sub sublist {
    my $self = shift; 
    return [ qw/ sub1 sub3 sub2 / ];
}

Below, we call them all for testing purposes, but you can also see how to call only one: 下面,我们将它们全部称为测试目的,但您也可以看到如何只调用一个:

foreach my $method (@$subs) {
  my $x = $instance->$method();
  say "$method returned $x";
}

Output: 输出:

in sub 1
sub1 returned 1
in sub 3
sub3 returned 3
in sub 2
sub2 returned 2

(Temporary placeholder here until/unless the original poster of the answer returns): (临时占位符在此处,除非答案的原始海报返回):

The trick is adding a dereference: 诀窍是添加一个解除引用:

$instance->${\$sublist->[$index]}(@args);

thus you can also do: 因此你也可以这样做:

$instance->${\$instance->sublist->[$index]}(@args);

otherwise it thinks it's a scalar to dereference. 否则它认为这是一个取消引用的标量。 (eg, Not a SCALAR reference at script.pl, line XX ). (例如, Not a SCALAR reference at script.pl, line XX )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM