如何从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
等), next
和break
也接受一个参数。
考虑以下:
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?