2015-04-21 5 views
0

У меня есть подразделение, которое читает текстовый файл 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. 
} 

В середине нескольких петель, & инициатор называется. Я хотел бы иметь это в модуле, который я могу использовать, но замените инициатор & на другие подсистемы из других модулей. Эти субмарины также должны иметь свои собственные ресурсы. Будет ли что-то вроде следующей работы или есть более элегантное решение?

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])); 

Примечание: Конечная файловая структура - Otherub.pm, Reader.pm и скрипт, который использует оба модуля.

+0

Что вы подразумеваете под «необходимостью иметь собственные входы»? Вы имеете в виду, что эти функции имеют разные входные параметры, чем '& инициатор'? Потому что, в этом случае, какой смысл заставить эту функцию (точнее, ссылку на функцию _) читать читателю? –

+1

Префиксные функции с '&' устарели в текущей версии perl. Теперь он имеет довольно специфический смысл, и лучше всего это избыточно. – Sobrique

ответ

1

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"]); 

не будет работать, потому что вы сразу же «работает», а затем посылает результат - which'll сделать свой $code_ref независимо от результат подпрограммы был.

Однако вы могли сделать анонимный юг, и передать:

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

Я хотел бы предложить, вы получаете излишне запутанные к тому моменту, хотя :)

+1

Спасибо за информацию! Это было действительно всеобъемлющее и информативное. – user3481208

1

Насколько я догадываюсь, , вы хотите передать функцию (ссылку) в качестве параметра. Что-то, как это должно работать для вас

# 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, как вы могли бы иметь intendend; вместо этого вы вызываете его и передаете результат soubroutine, учитывая параметры par читателю.