与
this question about iterating over subroutine references类似,作为回答
this question about a OO dispatch table的结果,我想知道如何在引用中调用方法引用,而不是先删除它,或者甚至可能.
例如:
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
那么,在HERE,我们可以做到:
my $ref = $subs->[$index]; $instance->$ref();
但是如果不首先删除引用,我们将如何做到这一点呢?
编辑:
更改了代码示例,以便人们不会对实现细节感到困惑(叹息,尽我所能).这与我给出的第一个链接之间的重要区别是该函数应该作为方法调用,而不是作为直接子例程调用.
编辑2:
请参阅discussion in the linked comment关于技术细节,以及为什么更长的方式(将subref存储到变量,然后调用它)可能更好.
解决方法
如上所述,你可以逃脱
$tests->[$index]();
因为你问题中的方法不是使用$self.
你可以明确地传递$instance,但这很笨重.更好的是模拟具有闭包的代理:
sub sublist { my $self = shift; my $sublist; for (qw/ sub1 sub3 sub2 /) { my $meth = $_; push @$sublist => sub { $self->$meth() }; } return $sublist; }
如果您想简洁,请使用
sub sublist { my $self = shift; return [ map { my $meth = $_; sub { $self->$meth() } } qw/ sub1 sub3 sub2 / ]; }
随机拨打一个仍然是
$tests->[$index]();
更新
通过can抓取subrefs似乎是不必要的复杂性.如果运行时确定要调用的方法名称列表,则可以大大简化代码:
sub sublist { my $self = shift; return [ qw/ sub1 sub3 sub2 / ]; }
下面,我们将它们全部称为测试目的,但您也可以看到如何只调用一个:
foreach my $method (@$subs) { my $x = $instance->$method(); say "$method returned $x"; }
输出:
in sub 1 sub1 returned 1 in sub 3 sub3 returned 3 in sub 2 sub2 returned 2