我一直在阅读Flanagan-Matz撰写的Ruby Programming Language一书
上下文:Proc.new和lambda w.r.t之间的区别返回语句
本书指出lambda中的返回应不引发LocalJumpError(因为lambdas类似于方法调用)。 lambda中的返回只退出lambda - 而不是包含迭代器的方法。
但是,以下代码片段另有说明。这里有什么问题?
def caller( aProc, switch)
puts "Start Caller"
case switch
when :normal_block; iterator &aProc
when :block_parameter; iterator_blockparam(&aProc)
else iterator_param(aProc)
end
puts "End Caller"
end
def iterator
puts "Begin iterator"
[1,2,3,4].each { |x| yield x }
puts "End iterator"
end
def iterator_blockparam(&block)
puts "Start Iterator wBlockParam"
puts "Block is {block.lambda? ? 'Lambda' : 'Proc'}"
[1,2,3,4].each { |x| block[x] }
puts "End Iterator wBlockParam"
end
def iterator_param(aProc)
puts "Start Iterator wParam"
puts "Block is {aProc.lambda? ? 'Lambda' : 'Proc'}"
[1,2,3,4].each{ |x| aProc[x]}
puts "End Iterator wParam"
end
# enclosing method Proc.new already returned.
no3proc = Proc.new{|x| return -101 if x == 3; puts x }
no3lambda = lambda{|x| return -101 if x == 3; puts x }
#~ caller( no3proc, :normal_block) #=> LocalJumpError
caller( no3lambda, :normal_block ) # => LJE
#~ caller( no3proc, :block_parameter) #=> LJE
#~ caller( no3lambda, :block_parameter) # works!
#~ caller(no3proc, :with_param) #=> LJE
#~ caller(no3lambda, :with_param) # works!
答案 0 :(得分:4)
LJE不是由于返回方法,而是返回调用块的数组迭代器。您无法从数组迭代器返回。通过简单地尝试从以下每个块返回来查看所复制的行为:
<击> 击><击>
[1,2,3] .each {| x |返回x}
LocalJumpError:意外返回
来自(irb):7
来自(irb):7:在'每个'中
来自(irb):7
编辑:好的,我把它拿回来,你可以退出迭代器。我的LJE是因为我在控制台(argh)。
编辑:好的,我看到了你的问题。基本问题是为什么block[x]
工作而yield x
没有工作(假设&amp; block是lambda)。 yield x
在块中解释代码并在数组迭代器的上下文中调用它,它将抛出LJE(如上所述),而block[x]
不会内联代码并且只返回块本身。所以,由于未能回答你的问题,我至少将其提炼为以下内容:
def call_as_block(&block)
block.call
end
def call_as_yield
yield
end
proc_return = Proc.new { return }
lambda_return = lambda { return }
call_as_block &proc_return # throws LJE
call_as_yield &proc_return # throws LJE
call_as_block &lambda_return # does NOT throw LJE
call_as_yield &lambda_return # throws LJE
所以差异似乎不在lambda和Proc之间,它的行为符合预期,但在通过yield
调用lambda和通过block.call
调用lambda之间。调用yield
似乎使lambda的行为就像它是Proc一样,并试图返回该方法的上下文。