开发者

How can I return something early from a block?

If I wanted to do something like this:

collection.each do |i|
   return nil if i == 3

   ..many lines of code here..
end

How would I get that effect? I know I could just wrap everything inside the block in a big if statement, but I'd like to avoid the nesting if possibl开发者_开发技巧e.

Break would not work here, because I do not want to stop iteration of the remaining elements.


next inside a block returns from the block. break inside a block returns from the function that yielded to the block. For each this means that break exits the loop and next jumps to the next iteration of the loop (thus the names). You can return values with next value and break value.


#!/usr/bin/ruby

collection = [1, 2, 3, 4, 5 ]

stopped_at = collection.each do |i|
   break i if i == 3

   puts "Processed #{i}"
end

puts "Stopped at and did not process #{stopped_at}"


In this instance, you can use break to terminate the loop early:

collection.each do |i|
  break if i == 3
  ...many lines
end

...of course, this is assuming that you're not actually looking to return a value, just break out of the block.


Although this is ancient, this still confuses me sometimes. I needed this for a more complicated use case with [].select {|x| }/[].reject {|x| }.

Common Use case

 [1,2,3,4,5].select{|x| x % 2 == 0 }
 => [2, 4] 

But I needed to yield a specific value for each iteration and continue processing

With more complicated logic:

[1,2,3,4,5].select{|x| if x % 2 == 0; next true; end; false }
 => [2, 4] 
# you can also use `next(true)` if it's less confusing

Also, since it's relevant to the thread, using break here will emit the single value you pass in if the conditional hits:

[1,2,3,4,5].select{|x| if x % 2 == 0; break(true); end; false }
 => true 
[1,2,3,4,5].select{|x| if x % 2 == 0; break(false); end; false }
 => false 
[1,2,3,4,5].select{|x| if x % 2 == 0; break('foo'); end; false }
 => "foo" 
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜