Perl do ... время и последняя команда - PullRequest
17 голосов
/ 26 октября 2011

Я только что столкнулся с очень странным поведением, которое я действительно не могу объяснить:

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 {...}?

Ответы [ 3 ]

29 голосов
/ 26 октября 2011

Блок 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 };
21 голосов
/ 26 октября 2011

С perldoc -f последний :

«последний» нельзя использовать для выхода из блока, который возвращает значение, такое как "eval {}", "sub {}" или "do {}"

16 голосов
/ 26 октября 2011

TLP прав. Стандартный обходной путь для этого (я просто ударил его сам) состоит в том, чтобы обернуть do / находясь в пустом блоке, который, интуитивно, уважает элементы управления циклом.

{ do {
    last;
} while 1; }

Блок снаружи поймает last. Если вы хотите обработать next, вы должны поместить блок внутрь.

do {{
    next;
}} while 1;

Блок внутри будет ловить next.

К сожалению, вы не можете сделать оба.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...