【问题标题】:Ending an iteration of a loop from a subroutine从子例程结束循环的迭代
【发布时间】:2014-09-12 12:16:48
【问题描述】:

我有一个带有 while 循环的程序,它有几个点,某些条件需要采取一些操作,然后跳过剩余的迭代。

因为这总是相同的代码,我想把它放在一个子程序中,但是当我尝试使用'next;'时作为 sub 中的最后一条语句,我收到一个警告(Exiting subroutine via next at ...),尽管它似乎按预期工作。

即没有子:

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

block/sub 中的其余代码太短了,除了下一个之外都放了; sub 中的语句几乎违背了使用子例程的目标。

我的问题是:

  • 正在使用“下一个;”以这种方式在子程序中可以,还是危险/不良做法?
  • 有没有更好的方法从子例程中跳过其余的迭代?
  • 如果没问题并且没有更好的方法,有没有办法抑制警告?

【问题讨论】:

    标签: perl loops subroutine


    【解决方案1】:

    很容易抑制警告。只需将以下行放在您的 next 上方:

    no warnings "exiting";
    

    出现警告是有原因的——在这样的辅助子程序中使用 next 可能会让下一个必须阅读代码的人(6 个月后可能是你!)感到困惑,因为 @987654324 @ 不会在循环块中按词汇出现。如果您只是阅读循环块,您可能不会注意到文件下方的next;如果您只是阅读子程序的定义,您可能不确定next 的用途。您需要一起阅读代码的两个部分才能理解它。这比直接在循环内使用next 更令人困惑。

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

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

    【讨论】:

      【解决方案2】:

      来自Learning perl 6th edition page 179(脚注)

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

      解决方案可能是其他人已经说过的,或者您可以在 sub 中进行额外的测试,例如

      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

      【讨论】:

        【解决方案3】:

        你的警告直觉可能是对的。正如您所说,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 可能不是一个好主意。)

        【讨论】:

        • 为什么在子跳过处使用圆括号?此处无需使用原型设计或签名。删除它们可能不那么令人困惑。
        【解决方案4】:

        如果这是好的做法,警告不会发出警告。使用您的函数,以便它提前返回而不是 next。您可以检查函数结果并决定是跳到下一个迭代,还是无条件跳到下一个,

        use warnings;
        
        sub foo {
          print ($_, "\n");
        }
        
        for (1..10) {
          foo(), next if $_ %2;;
        }
        

        【讨论】:

          【解决方案5】:

          您可以通过将truthy 返回next 和falsey 以使用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;
          }
          

          【讨论】:

            猜你喜欢
            • 2019-03-30
            • 2021-12-15
            • 1970-01-01
            • 1970-01-01
            • 2018-04-13
            • 2012-09-24
            • 2013-04-23
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多