从一个子程序结束一个循环迭代

问题描述:

我有一个while循环的程序,它有几个点,其中某些条件需要采取一些动作,然后跳过剩余的迭代。因为这将始终是相同的代码,我想把它放在一个子程序中,但是当我尝试使用'next'时,作为子文件中的最后一个语句,我得到了一个警告(通过下一个...的退出子例程),尽管它似乎按预期工作。从一个子程序结束一个循环迭代

即没有子:

while (#condition) { 

    ## do stuff 

    if (#condition to skip iteration) { 
     ## action 
     next; 
    } 

    ## do more stuff, with the above block repeated several times 
} 

与子:

while (#condition) { 

    ## do stuff 

    &skip if (#condition to skip iteration); 

    ## do more stuff, with more calls to &skip 
} 

sub skip() { 
    ## action 
    next; 
} 

在块中的代码的其余部分/子很短,使得将所有但下;子语句中的语句几乎无法使用子例程的对象。

我的问题是:

  • 是用 '未来;'在这样的子程序中是好的,还是危险的/糟糕的做法?
  • 有没有更好的方法从子程序中跳过其余的迭代?
  • 如果确定并没有更好的方法,是否有办法抑制警告?

您的警告本能可能是正确的。正如你所说,next只是不是一种嵌入子程序中的声明。即使你不喜欢它,这是几乎可以肯定更好:

while (#condition) { 

    ## do stuff 

    &skip, next if (#condition to skip iteration); 

    ## do more stuff, with more calls to &skip 
} 

sub skip() { 
    ## action 
} 

(我正好有对非标准编程技术比较宽松的态度​​,特别是如果他们不滥用如果你感到强烈嵌入next。在这种情况下,我不会和你争论,因为这是你的程序,但是,既然你已经提出了建议,我同意你的直觉,即嵌入next可能不是一个好主意。)

+0

为什么在子跳过时使用圆括号?无需在这里使用原型或签名。也许不那么容易混淆删除它们。 – jmmeier 2014-09-14 14:33:12

如果这是一个好的做法,警告不会警告。使用你的功能,以便它返回的时间早,而不是next。您可以检查函数的结果,并决定是否跳过下一次迭代,或无条件地跳到下一个,

use warnings; 

sub foo { 
    print ($_, "\n"); 
} 

for (1..10) { 
    foo(), next if $_ %2;; 
} 

学习Perl的第六版第179页(脚注)

它可能不是一个好主意,但是你可以在子程序中使用这些循环控制 运算符来控制子程序之外的循环。也就是说,如果在循环块中调用子程序 ,并且在子程序内没有运行 的循环块时子程序最后执行,则控制流将跳转到主代码中的 循环块之后。 这种在子程序中使用来自 的循环控制的能力可能在未来版本的Perl中消失,和 可能会错过它。

的解决方案可能是什么已经说了别人,或者你可以在子做额外的测试,像

use strict; 
use warnings; 

while(<>) { 
    chomp; 
    maybeskip($_) && next if m/2/; #maybe skip if match 2 
    print "$_\n"; 
} 

sub maybeskip { 
    $_[0] !~ m/0/; #skip only if not match 0 
    # the sub retuns the result of the last executed expression 
    # if this is not wanted you should use explicit return $value; 
} 

seq 25 | perl script 

打印:

1 
3 
4 
5 
6 
7 
8 
9 
10 
11 
13 
14 
15 
16 
17 
18 
19 
20 

例如跳过所有匹配的2但不是20

这很容易抑制警告。只要将下面这行你next以上:

no warnings "exiting"; 

的警告是有原因的 - 在一个辅助子使用next一样,可以是谁拥有读码旁边的人混乱(谁可能是你在6个月的时间!),因为next不会出现在循环块的词汇中。如果您刚刚读取循环块,则可能没有注意到该文件后面的next;如果您只是阅读子例程的定义,则可能不确定next的用途。您需要将两部分代码一起阅读才能理解它。这使得它比直接在循环内部使用next更令人困惑。

此外,它限制了您刚刚定义的skip()子版的重用性。想要在另一个循环内重新使用那个skip()子?你最好希望跳跃逻辑在新循环中仍然有意义。

如果你已经考虑了所有这些,并且仍然想继续,那么就像我上面显示的那样禁用警告。 警告不是错误,它们只是警告。这就是为什么警告被称为“警告”。它们旨在将您的注意力引向潜在的问题;不要阻止你做出你认为有用的事情。

可以通过将truthy返回到next并假装继续使用and运算符来将部分/全部跳过条件放入子例程中。

while (#condition) { 

    ## do stuff 

    &skip and next if (#condition to skip iteration); 

    ## or like this 
    next if (#condition to skip iteration) and &skip; 

    ## or like this 
    (#condition to skip iteration) and &skip and next; 

    ## do more stuff, with more calls to &skip 
} 

sub skip() { 
    ## action 
    return $common_skip_condition; 
}