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怎么会这样?调用do
undef$record。如果
$dataFile->getRecord()
死亡,则
$record
未定义。任何跳过
continue
块的操作都将结束循环或跳过条件。假设在第一次迭代之前未定义
$record
,则调用
$dataFile->getRecord
时,
$record
将始终未定义,并始终在
$LT\u dataFile->encode($record>时定义)被调用。