代码之家  ›  专栏  ›  技术社区  ›  Fluffy

如何打破红宝石的外循环?

  •  53
  • Fluffy  · 技术社区  · 16 年前

    在Perl中,可以打破这样的外部循环:

    AAA: for my $stuff (@otherstuff) {
             for my $foo (@bar) {
                 last AAA if (somethingbad());
             }
          }
    

    (语法可能错误),它使用循环标签从内部循环中断外部循环。红宝石中有相似的东西吗?

    8 回复  |  直到 8 年前
        1
  •  36
  •   sawa    13 年前

    您需要的是非本地控制流,Ruby有几个选项可供选择:

    • 延续,
    • 例外情况,以及
    • throw / catch

    连续性

    赞成的意见:

    • 延续是非本地控制流的标准机制。事实上,你可以建立 任何 非本地控制流(子程序、过程、函数、方法、协程、状态机、生成器、条件、异常)位于它们之上:它们几乎是 GOTO .

    欺骗:

    • 延续不是Ruby语言规范的强制部分,这意味着一些实现(xruby、jruby、ruby.net、ironruby)没有实现它们。所以,你不能依赖他们。

    例外情况

    赞成的意见:

    • 有一篇论文从数学上证明了异常比连续性更强大。IOW:他们可以做任何延续可以做的事情,等等,所以您可以使用它们来替代延续。
    • 例外情况是普遍存在的。

    欺骗:

    • 他们被称为“例外”,这使人们认为他们是“只为特殊情况”。这意味着三件事:阅读代码的人可能不理解它,实现可能没有针对它进行优化(是的,异常 几乎所有Ruby实现都非常缓慢)最糟糕的是,只要他们一看你的代码,你就会不停地抱怨“异常只适用于特殊情况”。(当然,他们甚至不会试图理解你在做什么。)

    / 抓住

    这大致是它的样子:

    catch :aaa do
      stuff.each do |otherstuff|
        foo.each do |bar|
          throw :aaa if somethingbad
        end
      end
    end
    

    赞成的意见:

    • 与例外情况相同。
    • 在Ruby1.9中,对控制流使用异常实际上是 语言规范的一部分 你说什么?循环、枚举器、迭代器等都使用 StopIteration 终止的例外情况。

    欺骗:

    • Ruby社区对它们的憎恨甚至超过了对控制流使用异常。
        2
  •  105
  •   rogerdpack    13 年前

    考虑 throw / catch . 通常,下面代码中的外部循环将运行五次,但使用throw可以将其更改为您喜欢的任何内容,并在过程中中断它。考虑一下这个完全有效的Ruby代码:

    catch (:done) do
      5.times { |i|
        5.times { |j|
          puts "#{i} #{j}"
          throw :done if i + j > 5
        }
      }
    end
    
        3
  •  29
  •   sepp2k    13 年前

    不,没有。

    您的选择是:

    • 将循环放入方法中,并使用返回值从外部循环中断
    • 从内部循环设置或返回一个标志,然后检查外部循环中的该标志,并在设置该标志时将其中断(这有点麻烦)
    • 使用投掷/接球突破循环
        4
  •  4
  •   Anno2001    13 年前
    while c1
     while c2
        do_break=true
     end
     next if do_break
    end
    

    或者“如果要断开就断开”,这取决于你想要什么

        5
  •  2
  •   Jeff Waltzer    16 年前

    也许这就是你想要的?(未经测试)

    stuff.find do |otherstuff|
      foo.find do
        somethingbad() && AAA
      end
    end
    

    find方法一直循环,直到块返回非空值或单击列表结尾。

        6
  •  0
  •   Jonas Elfström    16 年前

    我知道我早上会后悔的,但简单地使用一个while循环就可以做到这一点。

    x=0
    until x==10
      x+=1
      y=0
      until y==10
        y+=1
        if y==5 && x==3
          x,y=10,10
        end
      end
      break if x==10
      puts x
    end
    

    这个 if y==5 && x==3 只是表达式变为真的一个例子。

        7
  •  0
  •   Metareven    11 年前

    在循环周围包装一个内部方法可以做到这一点 例子:

    test = [1,2,3]
    test.each do |num|
      def internalHelper
        for i in 0..3 
          for j in 0..3
            puts "this should happen only 3 times"
            if true
              return
            end
          end
        end
      end
    internalHelper
    end
    

    在这里,您可以在任何for循环内执行检查,并在满足条件后从内部方法返回。

        8
  •  0
  •   Stephen LAI    8 年前

    您可以考虑添加一个标记,该标记设置在内部循环中,用于控制外部循环。

    “下一个”外循环

    for i in (1 .. 5)
      next_outer_loop = false
      for j in (1 .. 5)
        if j > i     
          next_outer_loop = true if j % 2 == 0
          break      
        end          
        puts "i: #{i}, j: #{j}"
      end            
      print "i: #{i} "                                                                                                                                                                             
      if next_outer_loop
        puts "with 'next'"
        next         
      end            
      puts "withOUT 'next'"
    end
    

    “中断”外部循环

    for i in (1 .. 5)
      break_outer_loop = false
      for j in (1 .. 5)
        if j > i
          break_outer_loop = true if i > 3
          break
        end
        puts "i: #{i}, j: #{j}"
      end
      break if break_outer_loop
      puts "i: #{i}"
    end
    
    推荐文章