如何从以下lambda抛出LocalJumpError?

时间:2010-02-08 13:09:57

标签: ruby lambda ruby-1.9

我一直在阅读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!

1 个答案:

答案 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一样,并试图返回该方法的上下文。