Perl 如何重写此评估块
这个代码闻起来。。。我怎样才能把它重写得更好Perl 如何重写此评估块,perl,Perl,这个代码闻起来。。。我怎样才能把它重写得更好 my $record; eval { while ( # undef $record here, so if getRecord() failed, nothing will be written # in the reject file do { undef $record; defined( $record = $dataFile->getRecord ) } ) {
my $record;
eval {
while (
# undef $record here, so if getRecord() failed, nothing will be written
# in the reject file
do { undef $record; defined( $record = $dataFile->getRecord ) }
) {
$LT_DataFile->encode($record);
}
1;
};
if ( my $error = $@ ) {
$rejectFile->writeRecord( $error, $record );
}
谢谢。您不需要catch部分中的变量,因为当执行到达那里时,它的内容将始终是
undef
。将其替换为文字值可以将$record
限制在较小的范围内
use Try::Tiny;
try {
while (defined(my $record = $dataFile->getRecord)) {
$LT_DataFile->encode($record);
}
} catch {
$rejectFile->writeRecord($_, undef); # T::T puts error in $_
}
好的,修改了我的答案 我认为这里真正的问题是如何处理错误。当您有多个地方可能出错时,乍一看,看到单个错误处理程序是令人困惑的。我看到两种选择 首先,保持与现在大致相同,但具体检查每种类型的错误:
my $record;
eval {
while (defined( $record = $dataFile->getRecord )) {
$LT_DataFile->encode($record);
}
};
if (my $error = $@) {
given ($error) {
when (/get record error/) { $rejectFile->writeRecord($_, undef); }
when (/encode error/) { $rejectFile->writeRecord($_, $record); }
}
}
这样,您就可以明确地处理错误。当然,使用Try::Tiny,这可以简化为以下内容
my $record;
try {
while (defined( $record = $dataFile->getRecord )) {
$LT_DataFile->encode($record);
}
} catch {
when (/get record error/) { $rejectFile->writeRecord($_, undef); }
when (/encode error/) { $rejectFile->writeRecord($_, $record); }
}
或者,您可以根据添加词法记录。这需要第二次评估或尝试,更接近问题并添加最后一次调用:
eval {
while (defined( my $record = $dataFile->getRecord )) {
eval { $LT_DataFile->encode($record) };
if (my $error = $@) { $rejectFile->writeRecord($error, $record); last }
}
};
if (my $error = $@) {
$rejectFile->writeRecord($error, undef);
}
不幸的是,这个方法不能与Try::Tiny一起使用,因为传递给Try的块实际上是子引用。我将重构,同时
循环到
while (defined( $record = $dataFile->getRecord )) {
$LT_DataFile->encode($record);
} continue {
undef $record;
}
在测试条件之前,在每次迭代之后执行continue
块。如果您的代码使用next
提前开始下一次迭代,则仍将调用它。如果您不太可能调用next
,则将代码简化为
while (defined( $record = $dataFile->getRecord )) {
$LT_DataFile->encode($record);
undef $record;
}
也可以。+1用于Try::Tiny。对于@est,执行评估
,然后单独测试$@
,在某些情况下,由于$@
是全局性的,可能会导致问题(遗漏错误、错误消息不正确)。改用Try::Tiny,因为它可以为您处理所有这些细节。如果出现错误,为什么说$record
将始终是undef
?大概encode
方法能够抛出错误,在这种情况下,$record
将是导致编码错误的记录。如果getRecord
是失败的方法,则只有undef
。如果$record是一个对象,则可以删除定义的,只需检查真实性:while(my$record=…)}
@以太:请记住,对象可以重载bool
,因此定义的对象可以计算为false。(或者,如果对象重载转换为字符串或数字,这些将用于确定真实性。)@cjm:objects可以,但人们希望它们能够智能地这样做,并返回逻辑结果——例如,在布尔上下文中计算为false的已定义对象可能指示无效或损坏的数据集,因此,检查此值可能正好满足调用者的需要。但是您忽略了解释为什么$record
需要undef
的注释。如果getRecord
抛出错误,您将报告上一条(非错误的)记录。而现在您遇到了相反的问题。如果encode
抛出错误,您将报告undef
,而不是导致错误的记录。该死,这是混淆代码。现在已经全部清理干净了。如果这是我的代码,我会编写单元测试来执行每个代码路径。这不会像预期的那样工作。。。。当$dataFile->getRecord()引发异常时,$record已经具有上一次迭代的值,因此$rejectFile->WriterRecord()获取了错误的信息。@est怎么会这样?调用doundef$record在循环的下一次迭代中,总是在条件之前调用code>。如果$dataFile->getRecord()
死亡,则$record
未定义。任何跳过continue
块的操作都将结束循环或跳过条件。假设在第一次迭代之前未定义$record
,则调用$dataFile->getRecord
时,$record
将始终未定义,并始终在$LT\u dataFile->encode($record>时定义)代码>被调用。