问题
The break statement for blocks (as per The Ruby Programming Language) is defined as follows:
it causes the block to return to its iterator and the iterator to return to the method that invoked it.
Therefore when the following code is run, it results in a LocalJumpError.
def test
puts "entering test method"
proc = Proc.new { puts "entering proc"; break }
proc.call # LocalJumpError: iterator has already returned
puts "exiting test method"
end
test
While the following code does not throw a LocalJumpError. What is special about the ampersand sign? Doesn't the ampersand sign implicitly use Proc.new?
def iterator(&proc)
puts "entering iterator"
proc.call # invoke the proc
puts "exiting iterator" # Never executed if the proc breaks
end
def test
iterator { puts "entering proc"; break }
end
test
In other words, I read the ampersand sign as a means of in-lining the Proc.new call. At which point the behavior should be just the same as the first code snippet.
def iterator (p = Proc.new { puts "entering proc"; break})
...
end
Disclaimer: I am newb learning the language (ruby 1.9.2), and therefore will appreciate references and a detailed synopsis.
回答1:
break
makes the block and the caller of the block return. In the following code:
proc = Proc.new { break }
The "caller" of the block which is converted to a Proc object is Proc.new. break
is supposed to make the caller of the block return, but Proc.new has already returned.
In this code:
def iterator(&b); b.call; end
iterator { break }
The caller of the block is iterator
, so it makes iterator
return.
回答2:
Here's the answer.
Ampersand is used to convert a proc to a block and a block to a proc.
I changed the example so as to relate to your case:
def run_my_code(&my_code)
puts 'before proc'
my_code.call
puts 'after proc'
end
run_my_code { puts "passing a block, accepting a proc"; break}
=> before proc
passing a block, accepting a proc
As you can see it didn't reach the 'after proc'
def run_my_code
yield
end
my_proc = Proc.new { puts "passing a proc instead of block"; break}
run_my_code &my_proc
=> passing a proc instead of block
LocalJumpError: break from proc-closure
from (pry):75:in `block in <main>'
In your second example you have a proc in result, the proc breaks from iterator
and returns to test
function.
def iterator(&proc)
puts 'entering iterator'
proc.call
puts 'exiting iterator'
end
def test
puts 'before test'
iterator { puts 'entering proc'; break }
puts 'after test'
end
=>before test
entering iterator
entering proc
after test
回答3:
It has to do with the difference between blocks, procs and lambdas - and their respective scopes.
I wrote a post about it back in 2009 that you might find useful: http://www.leonardoborges.com/writings/2009/07/22/procs-lambdas-blocks-whats-the-difference/
Hope this helps.
来源:https://stackoverflow.com/questions/8888958/why-does-the-break-statement-in-ruby-behave-differently-when-using-proc-new-v-t