以下是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
中添加任何特定内容。
答案 0 :(得分:707)
使用关键字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
将控件移出块,调出块的迭代器,以及调用迭代器后的第一个表达式:
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
总是会导致封闭方法返回,无论它在块中嵌套的程度如何(除了lambda之外):
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
答案 1 :(得分:54)
我希望能够突破一个块 - 有点像转发,与循环无关。实际上,我想要在不终止循环的情况下中断循环中的块。为此,我使块成为一个迭代循环:
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员工。
答案 2 :(得分:37)
如果您希望您的块返回有用的值(例如,在使用#map
,#inject
等时),next
和break
也接受参数。< / p>
请考虑以下事项:
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
答案 3 :(得分:19)
使用关键字break
代替return
答案 4 :(得分:8)
也许您可以使用内置方法在数组中查找特定项目,而不是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
答案 5 :(得分:2)
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
答案 6 :(得分:-2)
要从ruby块中突破,只需使用return
关键字
return if value.nil?