在perl中的嵌套while循环中中断最内层循环:找不到Label

时间:2014-04-20 12:26:18

标签: perl

我遇到了在双嵌套while循环中突破最里面的封闭循环的问题。 考虑:

use v5.14;

my $i=0;
while ($i<=1) {
    my $j=0;
    do {
        last if $j==2;
        say $j++;
    } while ($j<4);
    $i++;
}

输出在这里:

0
1

而预期的输出应为:

0
1
0
1

在最里面的封闭循环中添加标签:

my $i=0;
while ($i<=1) {
    my $j=0;
    LINE: do {
        last LINE if $j==2;
        say $j++;
    } while ($j<4);
    $i++;
}

给出错误:

Label not found for "last LINE" at ./p.pl line 9.

5 个答案:

答案 0 :(得分:8)

您只能在使用last的循环中使用nextredoBLOCK

  • while (EXPR) BLOCK
  • until (EXPR) BLOCK
  • for (LIST) BLOCK
  • for (EXPR; EXPR; EXPR) BLOCK
  • BLOCK

您不能在语句修饰符 [1] 创建的循环上使用它们。

  • EXPR while EXPR;
  • EXPR until EXPR;

do BLOCK while EXPR;只是EXPR while EXPR;的一个案例。该循环没有BLOCK last可供使用。它只是一个while语句修饰符,它正在修改do函数 [2] 。正在修改的do函数有BLOCK,但do不是循环。


您可以向last添加一个循环,例如通常只执行一次的裸循环(BLOCK)。

my $i=0;
while ($i<=1) {
    LOOP: {
        my $j=0;
        do {
            last if $j==2;
            say $j++;
        } while ($j<4);
    }
    ++$i;
}

但如果我们能确保++$i总是被执行,我们就可以next外部循环。

my $i=0;
while ($i<=1) {
    my $j=0;
    do {
        next if $j==2;
        say $j++;
    } while ($j<4);
} continue {
    ++$i;
}

以上简化为

for (my $i=0; $i<=1; ++$i) {
    my $j=0;
    do {
        next if $j==2;
        say $j++;
    } while ($j<4);
}

简化为

for my $i (0..1) {
    my $j=0;
    do {
        next if $j==2;
        say $j++;
    } while ($j<4);
}

当然,这假设我们需要保留do while。如果没有,我们可以写

for my $i (0..1) {
    for my $j (0..3) {
        last if $j==2;
        say $j;
    }
}

  1. 或者我想。事实证明它适用于for !!!!

    >perl -we"print($_), (($_ == 5) && last) for 1..10; print(qq{\ndone\n});"
    12345
    done
    
  2. 嗯,不是“仅仅”。它特别容易进行底部测试,而不是经过顶级测试。

答案 1 :(得分:3)

正如perldoc do所有人都已说过:

  
      
  • do BLOCK

         

    不是真正的功能。返回BLOCK指示的命令序列中最后一个命令的值。当由whileuntil循环修饰符修改时,在测试循环条件之前执行一次BLOCK。 (在其他语句中,循环修饰符首先测试条件。)

         

    BLOCK是否计为循环,因此循环控制语句nextlastredo不能用于离开或重新启动块。有关替代策略,请参阅perlsyn

  •   

关于这一点的更深层次的部落知识是你应该为单行或最多两行声明保留这些语句修饰符。

如果你想要一个多线程块是一个循环,编码器应该能够从第一行观察到。因此,不要使用带有do BLOCK的语句修饰符,而是设置一个无限循环并创建测试以在最后突破它:

while (1) {
    ...

    last if EXPR;
}

这会将你有点人为的例子改为:

use v5.14;

my $i = 0;
while ($i <= 1) {
    my $j = 0;
    while (1) {
        last if $j == 2;
        say $j++;
        last if $j >= 4;
    }
    $i++;
}

答案 2 :(得分:2)

您无法在last块中使用do{},但您可以

my $i=0;
while ($i<=1) {
    my $j=0;
    LINE: { 
      do {
        last LINE if $j==2;
        say $j++;
      } while ($j<4); 
    }
    $i++;
}

my $i=0;
OUTER: while ($i<=1) {
    my $j=0;
    LINE: do {
        next OUTER if $j==2;
        say $j++;
    } while ($j<4);
}
continue {
    $i++;
}

答案 3 :(得分:1)

如果你真的必须:

my $i=0;
while ($i++<=1) {
    my $j=0;
    LINE: {
      do {
        last LINE if $j==2;
        say $j++;
      } while ($j<4);
    }
}

答案 4 :(得分:1)

正如其他人所说,您不能将lastdo

一起使用
  

执行BLOCK不算作循环,因此循环控制语句next,last或redo不能用于离开或重启块。

另一种解决方案是使用另一个while循环:

my $i = 0;
while ($i <= 1) {
    my $j = 0;
    while($j < 4) {
        last if $j == 2;
        say $j++;
    }
    $i++;
}

或使用for循环:

for my $i (0 .. 1) {
    for my $j (0 .. 3) {
        last if $j == 2;
        say $j;
    }
}