2010-06-18 3 views
2

Этот код пахнет ... как его переписать лучше?Как переписать этот блок eval

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 = [email protected]) { 
    $rejectFile->writeRecord($error, $record); 
} 

Спасибо.

ответ

2

Хорошо, переработал мой ответ.

Я думаю, что проблема заключается в том, как вы справляетесь с ошибками. На первый взгляд сбивает с толку, чтобы увидеть один обработчик ошибок, когда у вас есть несколько мест, где все может пойти не так. Я вижу две альтернативы.

Во-первых, держать его в основном такой же, как у вас есть сейчас, но конкретно проверить для каждого типа ошибок:

my $record; 
eval { 
    while (defined($record = $dataFile->getRecord)) { 
     $LT_DataFile->encode($record); 
    } 
}; 
if (my $error = [email protected]) { 
    given ($error) { 
     when (/get record error/) { $rejectFile->writeRecord($_, undef); } 
     when (/encode error/)  { $rejectFile->writeRecord($_, $record); } 
    } 
} 

Таким образом, вы явно в том, как вы справляетесь свои ошибки. Конечно, с Try :: Крошечный, это упрощает в следующем

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. Это требует второго Eval или попытаться, ближе к проблеме и добавления last вызова:

eval { 
    while (defined(my $record = $dataFile->getRecord)) { 
     eval { $LT_DataFile->encode($record) }; 
     if (my $error = [email protected]) { $rejectFile->writeRecord($error, $record); last } 
    } 
}; 
if (my $error = [email protected]) { 
    $rejectFile->writeRecord($error, undef); 
} 

К сожалению, этот метод не будет работать с Try :: Крошечными, так как блоки, передаваемые попробовать на самом деле subrefs.

+0

Но вы проигнорировали комментарий, объясняющий, почему '$ record' должен быть' undef'. Если 'getRecord' выдает ошибку, вы будете сообщать о предыдущей (не ошибочной) записи. – cjm

+0

Дерп, действительно. Исправлена. –

+0

И теперь у вас есть противоположная проблема. Если 'encode' выдает ошибку, вы будете сообщать' undef' вместо записи, вызвавшей ошибку. – cjm

8

Вам не нужна переменная в ловушке, потому что при ее поступлении ее содержимое всегда будет 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

+1 для Try :: Tiny. Для @est выполнение 'eval', а затем отдельного тестирования' $ @ 'может вызвать проблемы (пропущенные ошибки, неправильные сообщения об ошибках) в некоторых случаях из-за того, что' $ @ 'является глобальным. Вместо этого используйте Try :: Tiny, потому что он обрабатывает все эти детали для вас. –

+4

Почему вы говорите, что '$ record' всегда будет' undef', если есть ошибка? Предположительно, метод 'encode' способен метать ошибки, и в этом случае' $ record' будет запись, которая вызвала ошибку кодирования. Это только 'undef', если' getRecord' - это метод, который не прошел. – cjm

+0

Если $ record - это объект, вы можете отказаться от 'defined' и просто проверить правдоподобие:' while (my $ record = ...))} ' – Ether

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

будет работать.

+0

Это не сработает, как ожидалось .... когда $ dataFile-> getRecord() выдает исключение, $ record уже имеет значение из предыдущей итерации, поэтому $ rejectFile-> writeRecord() получает неверную информацию. – est

+0

@est как так? Вызов 'undef $ record;' всегда будет вызываться перед условным в следующей итерации цикла. Если '$ dataFile-> getRecord()' умирает, тогда '$ record' является undef. Любое действие, которое пропустит блок 'continue', либо закончит цикл, либо пропустит условное. Предполагая, что '$ record' не определен до первой итерации, тогда' $ record' всегда будет неопределенным, когда вызывается '$ dataFile-> getRecord' и всегда определяется, когда' $ LT_DataFile-> encode ($ record); 'вызывается , –

Смежные вопросы