如何重写此eval块

时间:2010-06-18 06:22:31

标签: 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 ) }
    ) {
        $LT_DataFile->encode($record);
    } 
    1;
};

if ( my $error = $@ ) {
    $rejectFile->writeRecord( $error, $record );
}

感谢。

3 个答案:

答案 0 :(得分:8)

您在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 $_
}

答案 1 :(得分:2)

好的,重写了我的答案。

我认为这里的 REAL 问题是你如何处理错误。当你有多个地方可能出错时,乍看之下看到一个错误处理程序是令人困惑的。我看到两种选择。

首先,保持它与现在大致相同,但具体检查每种类型的错误:

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

或者,您可以按Daxim's answer添加词法记录。这需要第二次评估或尝试,更接近问题并添加last电话:

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的块实际上是subrefs。

答案 2 :(得分:2)

我会将while循环重构为

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;
}

也可以。