Perl do... while и last command
Я только что столкнулся с очень странным поведением, которое я действительно не могу объяснить:
do {
my $qry = $self->getHTMLQuery(undef, $mech->content());
next if (!defined($qry));
push(
@prods,
map { 'http://www.XXXXYYYX.com'.$_->attr('href') }
$qry->query('div.prodInfo div.prodInfoBox a.prodLink.GridItemLink')
);
$qry->delete();
$TEST++;
last if ($TEST >= 10);
} while(eval { $mech->follow_link(class => 'jump next') });
print "WHILE ENDED\n";
Приведенный выше код никогда не печатает "WHILE ENDED", хотя он, похоже, выходит из цикла while, когда $TEST
>= 10.
Но следующий код печатает "WHILE ENDED":
do {
my $qry = $self->getHTMLQuery(undef, $mech->content());
next if (!defined($qry));
push(
@prods,
map { 'http://www.XXXXYYYX.com'.$_->attr('href') }
$qry->query('div.prodInfo div.prodInfoBox a.prodLink.GridItemLink')
);
$qry->delete();
$TEST++;
} while(eval { $mech->follow_link(class => 'jump next') } && $TEST <= 10);
print "WHILE ENDED\n";
В обоих тестах начальное значение $TEST
равно 0.
Является ли поведение last
в do...while
отличным от for
и while {...}
?
Ответы
Ответ 1
A do
блок с модификатором цикла не считается реальным циклом до next
, last
и redo
. Это упоминается в perlsyn, где вы найдете отзыв, который Шверн упомянул об окружающем его блоке, чтобы сделать работу last
. Но это не будет работать с next
, потому что пустой блок выполняется только один раз, поэтому next
действует как last
. Чтобы сделать работу next
, вы можете поместить пустой блок внутри do
, но тогда last
будет действовать как next
.
Если вам нужны как next
, так и last
для работы с do ... while
, самый простой способ - использовать бесконечный цикл с реальным условием в блоке continue
. Эти 2 цикла эквивалентны, за исключением того, что второй представляет собой реальный цикл, поэтому он работает с next
и last
:
do { ... } while condition;
while (1) { ... } continue { last unless condition };
Ответ 2
Из perldoc -f last:
"last" не может использоваться для выхода из блока, который возвращает значение, например "eval {}", "sub {}" или "do {}"
Ответ 3
TLP является правильным. Стандартная работа для этого (я просто попал в нее сам) - это обернуть do/while в незакрытом блоке, который, интуитивно-интуитивно, будет уважать элементы управления контуром.
{ do {
last;
} while 1; }
Блок снаружи поймает last
. Если вы хотите обрабатывать next
, вам нужно поместить блок внутри.
do {{
next;
}} while 1;
Внутри блока будет ломаться next
.
К сожалению, вы не можете обойти оба.