如何从ruby块跳出来?

这里是Bar#do_things

 class Bar def do_things Foo.some_method(x) do |x| y = x.do_something return y_is_bad if y.bad? # how do i tell it to stop and return do_things? y.do_something_else end keep_doing_more_things end end 

这里是Foo#some_method

 class Foo def self.some_method(targets, &block) targets.each do |target| begin r = yield(target) rescue failed << target end end end end 

我想过使用raise,但是我试图使它成为通用的,所以我不想在Foo任何具体的东西。

使用next关键字。 如果您不想继续下一个项目,请使用break

当在一个块中使用next一个时,它会导致块立即退出,将控制返回到迭代器方法,然后可以通过再次调用块来开始新的迭代:

 f.each do |line| # Iterate over the lines in file f next if line[0,1] == "#" # If this line is a comment, go to the next puts eval(line) end 

在块中使用时, break将控制移出块,从调用该块的迭代器中移出,并移至迭代器调用后的第一个expression式:

 f.each do |line| # Iterate over the lines in file f break if line == "quit\n" # If this break statement is executed... puts eval(line) end puts "Good bye" # ...then control is transferred here 

最后,在块中使用return

return总是导致封闭的方法返回,不pipe在块内embedded的深度如何(除了lambdas):

 def find(array, target) array.each_with_index do |element,index| return index if (element == target) # return from find end nil # If we didn't find the element, return nil end 

我希望能够突破一个障碍 – 就像是一个前进的转折点,而不是一个循环。 实际上,我想要中断一个循环中的块而不终止循环。 为了做到这一点,我做了一个单迭代循环:

 for b in 1..2 do puts b begin puts 'want this to run' break puts 'but not this' end while false puts 'also want this to run' end 

希望这可以帮助下一个基于主题行的Google员工。

如果你想要你的块返回一个有用的值(例如,当使用#map#inject等), nextbreak也接受一个参数。

考虑以下:

 def contrived_example(numbers) numbers.inject(0) do |count, x| if x % 3 == 0 count + 2 elsif x.odd? count + 1 else count end end end 

等同使用next

 def contrived_example(numbers) numbers.inject(0) do |count, x| next count if x.even? next (count + 2) if x % 3 == 0 count + 1 end end 

当然,你总是可以将所需的逻辑提取到一个方法中,然后在块中调用它:

 def contrived_example(numbers) numbers.inject(0) { |count, x| count + extracted_logic(x) } end def extracted_logic(x) return 0 if x.even? return 2 if x % 3 == 0 1 end 

使用关键字break而不是return

也许你可以使用内置的方法来查找一个数组中的特定项目,而不是each targets ,手工完成任何事情。 几个例子:

 class Array def first_frog detect {|i| i =~ /frog/ } end def last_frog select {|i| i =~ /frog/ }.last end end p ["dog", "cat", "godzilla", "dogfrog", "woot", "catfrog"].first_frog # => "dogfrog" p ["hats", "coats"].first_frog # => nil p ["houses", "frogcars", "bottles", "superfrogs"].last_frog # => "superfrogs" 

一个例子就是做这样的事情:

 class Bar def do_things Foo.some_method(x) do |i| # only valid `targets` here, yay. end end end class Foo def self.failed @failed ||= [] end def self.some_method(targets, &block) targets.reject {|t| t.do_something.bad? }.each(&block) end end 

next在这个简单的例子中break似乎做了正确的事情!

 class Bar def self.do_things Foo.some_method(1..10) do |x| next if x == 2 break if x == 9 print "#{x} " end end end class Foo def self.some_method(targets, &block) targets.each do |target| begin r = yield(target) rescue => x puts "rescue #{x}" end end end end Bar.do_things 

输出:1 3 4 5 6 7 8

要打破循环或退出循环只是简单地使用 返回 next关键字 如果element.nil返回? next if element.nil?