2011-10-25 23 views
14

Tôi vừa mới gặp phải một số hành vi rất kỳ quặc mà tôi thực sự không thể giải thích:Perl do ... while và lệnh trước

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

Đoạn mã trên không bao giờ in "KHI KẾT THÚC" mặc dù nó có vẻ đi ra khỏi vòng lặp while khi $TEST> = 10

Nhưng đoạn mã sau không in "kHI KẾT THÚC":

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

trong cả hai bài kiểm tra, các giá trị ban đầu của $TEST là 0.

Hành vi của last trong do...while khác với trong forwhile {...}?

+0

tôi giả sử lần thứ hai bạn nói "mã ở trên", bạn thực sự có nghĩa là "mã * bên dưới * " – TLP

Trả lời

23

A do khối có công cụ sửa đổi lặp không được tính là vòng lặp thực theo như next, lastredo. Điều này được đề cập trong perlsyn, nơi bạn sẽ tìm thấy mũi mà Schwern đề cập đến xung quanh nó với một khối trống để làm cho công việc last. Nhưng điều đó sẽ không hoạt động với next, bởi vì một khối trống chỉ được thực hiện một lần, vì vậy next hoạt động như last. Để thực hiện tác vụ next, bạn có thể đặt khối trống bên trongdo, nhưng sau đó last sẽ hoạt động như next.

Nếu bạn cần cả hai nextlast để làm việc với do ... while, cách dễ nhất là sử dụng vòng lặp vô hạn với điều kiện thực tế trong khối continue. Những 2 vòng là tương đương, ngoại trừ việc thứ hai là một vòng lặp thực, vì vậy nó hoạt động với next & last:

do { ... } while condition; 
while (1) { ... } continue { last unless condition }; 
+0

Giải thích đầy đủ, cảm ơn! – snoofkin

21

Từ perldoc -f last:

"cuối cùng" không thể được sử dụng để thoát khỏi một khối mà trả về một giá trị như "eval {}", "tiểu {}" hoặc "làm {}"

14

TLP là đúng. Các tiêu chuẩn làm việc xung quanh cho điều này (tôi chỉ cần nhấn nó bản thân mình) là để bọc làm/trong khi trong một khối trần mà, truy cập trực giác, không tôn trọng điều khiển vòng lặp.

{ do { 
    last; 
} while 1; } 

Khối ngoài sẽ bắt last. Nếu bạn muốn xử lý next bạn phải đặt khối bên trong.

do {{ 
    next; 
}} while 1; 

Khối bên trong sẽ bắt được next.

Rất tiếc, bạn không thể thực hiện cả hai.

+1

Điều đó sẽ sửa' cuối cùng', nhưng nó sẽ không sửa 'tiếp theo'. Với một khối trần, hai giá trị này tương đương nhau (vì các khối trống chỉ được thực hiện một lần). – cjm

+0

@cjm Tốt bắt. Và tôi phát hiện bạn không thể làm cả hai.:-( – Schwern

+0

Vâng, bạn _could_, nhưng bạn phải đặt một nhãn trên khối ngoài và sau đó sử dụng 'LABEL cuối cùng '. Và đó chỉ là yêu cầu lỗi, bởi vì nếu bạn quên nhãn và chỉ gõ' last', nó sẽ hoạt động như 'next' thay thế. – cjm

Các vấn đề liên quan