perl - Perl 中是否可以要求进行子例程调用?

标签 perl compiler-errors subroutine required

我对 Perl 的了解还不够,甚至不知道我到底想要什么,但我正在编写一系列子例程,供许多单独的脚本使用,这些脚本都处理不同的传入平面文件。这个过程远非完美,但这是我必须处理的,我正在尝试为自己建立一个小型的潜艇库,使我更容易管理这一切。每个脚本处理不同的传入平面文件,具有自己的格式、排序、分组和输出要求。一个常见的方面是,我们有一些小文本文件,其中包含用于命名输出文件的计数器,以便我们没有重复的文件名。

因为每个文件的数据处理不同,所以我需要打开文件来获取计数器值,因为这是一个常见的操作,我想将其放在子中以检索计数器。但接下来需要编写具体的代码来处理数据。并且想要第二个子,它允许我在处理数据后用计数器更新计数器。

如果调用第一个子调用,是否有办法使第二个子调用成为必需?理想情况下,如果它甚至可能是一个错误,会阻止脚本运行,就像语法错误一样。

编辑:这里有一些[丑陋且简化的]伪代码,可以更好地了解当前的流程:

require "importLibrary.plx";

#open data source file
open DataIn, $filename;

# call getCounterInfo from importLibrary.plx to get 
# the counter value from counter file
$counter = &getCounterInfo($counterFileName);

while (<DataIn>) {
  # Process data based on unique formatting and requirements
  # output to task files based on requirements and name files 
  # using the $counter increment $counter
}

#update counter file with new value of $counter
&updateCounterInfo($counter);

最佳答案

我不太明白你在尝试什么,但你总是可以让你的潜艇可插入:

我们有一个子process_file。它采用一个子例程作为参数来执行主要处理:

our $counter;
sub process_file {
   my ($subroutine, @args) = @_;
   local $counter = get_counter();
   my @return_value = $subroutine->(@args);
   set_counter($counter);
   return @return_value;
}
# Here are other sub definitions for the main processing
# They can see $counter and always magically have the right value.
# If they assign to it, the counter file will be updated afterwards.

假设我们有一个子process_type_A,我们就可以这样做

my @return_values = process_file(\&process_type_A, $arg1, $arg2, $arg3);

其行为与 process_type_A($arg1, $arg2, $arg3) 类似,除了额外的调用堆栈帧和 $counter 设置。

如果您更喜欢传递名称而不是代码引用,我们也可以安排。

package MitchelWB::FileParsingLib;
our $counter;
our %file_type_processing_hash = (
  "typeA" => \&process_type_A,
  "typeB" => \&process_type_B,
  "countLines" => sub { # anonymous sub
     open my $fh, '<', "./dir/$counter.txt" or die "cant open $counter file";
     my $lines = 0;
     $lines++ while <$fh>;
     return $lines;
  },
);

sub process_file {
   my ($filetype, @args) = @_;
   local $counter = get_counter();
   # fetch appropriate subroutine:
   my $subroutine = $file_type_processing_hash{$filetype};
   die "$filetype is not registered" if not defined $subroutine;  # check for existence
   die "$filetype is not assigned to a sub" if ref $subroutine ne 'CODE';  # check that we have a sub
   # execute
   my @return_value = $subroutine->(@args);
   set_counter($counter);
   return @return_value;
}
...;
my $num_of_lines = process_file('countLines');

编辑:最优雅的解决方案

或者:属性真的很简洁

为什么要进行愚蠢的回调?为什么要额外的代码?为什么要调用约定?为什么要分派(dispatch)表?虽然它们都非常有趣且灵活,但还有一个更优雅的解决方案。我刚刚忘记了一小部分信息,但现在一切都已就位了。 Perl 具有“属性”,在其他语言中称为“注释”,它允许我们对代码或变量进行注释。

定义新的 Perl 属性很容易。我们使用 Attribute::Handlers 并定义一个与您要使用的属性同名的子组件:

sub file_processor :ATTR(CODE) {
  my (undef, $glob, $subroutine) = @_;
  no strict 'refs';
  ${$glob} = sub {
    local $counter = get_counter();
    my @return_value = $subroutine->(@_);
    set_counter($counter);
    return @return_value;
}

我们使用属性:ATTR(CODE)来表示这是一个适用于子例程的属性。我们只需要两个参数,我们想要注释的子例程的全名,以及子例程的代码引用。

然后我们关闭一部分严格性,以使用 ${$glob} 重新定义 sub。这有点高级,但它本质上只是访问内部符号表。

我们用上面给出的 process_file 的简化版本替换带注释的子文件。我们可以直接传递所有参数 (@_),无需进一步处理。

毕竟,我们向您之前使用的潜艇添加了一小段信息:

sub process_type_A :file_processor {
  print "I can haz $counter\n";
}

...它只是进行替换而无需进一步修改。使用库时这些更改是不可见的。我知道这种方法的限制,但在编写普通代码时不太可能遇到它们。

关于perl - Perl 中是否可以要求进行子例程调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12358690/

相关文章:

c++ - 为什么未命名的结构不能用作尾随返回类型?

Perl:将巨大字符串列表传输到子例程而不复制它们

windows - 如何在 Windows 上使用 Perl 优雅地打印 %z(时区)格式?

perl - 如何使用 mod_perl 和 CGI​​::Application 提供临时文件下载?

linux - 如何使用 sed 或 Perl 删除多行 block 中的部分行?

regex - 在perl中按换行符拆分正则表达式匹配

syntax - 这些代码属于哪个 Fortran 标准?

perl - 我可以将常规参数与 CGI::Application::Dispatch 一起使用吗?

visual-studio-2008 - 关于 VS2008 C++/CLI 中的重载问题

gcc - 为 ARM 交叉编译 zlib