内部子程序发生变化的嵌套模块化子程序

Nested modular subroutines where the inner subroutine changes

我有一个分块读取 FASTA 文本文件的子程序。

sub reader {
    foreach my $line (<IN>) {   # read line by line
        chomp $line;
        if ($line =~ m/^>/) {   # if it's a title
            &initiator($title, $seq) unless $firsttitle == 1;
            $firsttitle = 0;
            ($title = $line) =~ s/^>//; # title without > at start
            $seq = '';  # new seq
        } else {
            $seq = $seq . $line;    # append seq lines
        }
    }
    &initiator($title, $seq);   # Do the thing for the last seq.
}

在几个循环的中间,调用了&initiator。我想把它放在一个我可以 "use" 的模块中,但是用其他模块中的其他 sub 替换 &initiator。这些潜艇也需要有自己的输入。像下面这样的工作还是有更优雅的解决方案?

use Reader qw(reader);
use Othersub qw(subroutine);
my @par = ('Mary', 'Lamb');
my %functions = (foo => \&Othersub::subroutine);
&reader($file_to_read, $functions{'foo'}($par[0], $par[1]));

注意:最终文件结构是 Othersub.pm、Reader.pm 和使用这两个模块的脚本。

Perl 允许您创建对事物的引用,这包括子例程和数组。

如果您要传递不同的参数,那么我建议您通过数组引用而不是您正在做的事情来传递。有点像这样:

use strict;
use warnings;

sub variable_args {
    my ( $code_ref, $array_ref ) = @_;
    #dereference code ref;
    #dereference array ref;
    &$code_ref( @$array_ref, "optional", "extra", "arg" );
}

sub foo_func {
    foreach (@_) {
        print "Foo $_\n";
    }
}

sub bar_func {
    print "BAR: ", join( ":", @_ ), "\n";
}


#could inline the functions as anonymous subs. I would avoid doing that
#unless they're pretty short/clear. 
my %functions = (
    'foo' => \&foo_func,
    'bar' => \&bar_func,
);

my %args_to_pass = (
    'foo' => [ "Mary", "Lamb" ],
    'bar' => [ "Some", "Fish", "Pie" ],
);


for my $thing ( "foo", "bar" ) {
    variable_args( $functions{$thing}, $args_to_pass{$thing} );
}

注意 - 在上面的示例中,您调用 &initiator。你不应该这样做。它是 Perl 4 中弃用的语法,并且是多余的(并且在某些情况下可能会产生一些不良后果)。

但我建议您这样做,而不是按照您的方式进行。你可以让它工作:

&reader($file_to_read, $functions{'foo'}($par[0], $par[1]));

但是当您尝试这样做时会发生什么,您将(可能)立即 运行 您的函数,并将其结果传递给 reader

例如:

variable_args ( &{$functions{'foo'}}("Mary", "Lamb"), ["more stuff"] );

不会工作,因为你会立即 'running' 它,然后发送结果 - 这将使你的 $code_ref 无论 结果如何 的子程序是。

但是你可以创建一个匿名子,然后传递:

variable_args( sub {
                     &{ $functions{'foo'} }( "Special", "Argument", @_ ) 
                   },
               $args_to_pass{'foo'} );

不过,我建议您在这一点上变得不必要地费解了:)

据我猜测,您想传递一个函数(引用)作为参数。 这样的东西应该适合你

# Script

use Reader qw(reader);
use Othersub qw(subroutine);

my @par = .... ; 
reader( $file_to_read , \&subroutine , @par);

# Reader.pm

sub reader {
    my $file = shift;
    my $initiator = shift;
    my @par = @_; 
    ...
    $initiator->( $file , @par)
    ...
}  

备注: 在代码的最后一行,您没有将函数 subroutine 传递给 reader,因为您可能有意向;相反,您调用它并传递 子例程的结果,给定参数 par 到 reader。