gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 10:41:13 25 4
gpt4 key购买 nike

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

因为每个文件对数据的处理是不同的,所以我需要打开文件来获取我的计数器值,因为这是一个常见的操作,我想把它放在一个sub中来检索计数器。但随后需要编写特定的代码来处理数据。并且想要一个允许我在处理完数据后用计数器更新计数器的子程序。

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

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

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环境。

如果您更喜欢传递名称而不是 coderefs,我们也可以安排。
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');

编辑:最优雅的解决方案

或者:属性真的很整洁

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

定义一个新的 Perl 属性很容易。我们 use 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com