ruby - 下面的 lambda 表达式如何抛出 LocalJumpError ?

标签 ruby lambda ruby-1.9

我一直在阅读 Flanagan-Matz 所著的《Ruby 编程语言》一书

上下文:Proc.new 和 lambda w.r.t return 语句之间的差异

这本书指出,lambda 中的返回不应引发 LocalJumpError (因为 lambda 类似于方法调用)。 lambda 中的 return 只是退出 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!

最佳答案

LJE 不是由于从方法中返回,而是由于从调用 block 的数组迭代器返回。您无法从数组迭代器返回。通过简单地尝试从以下每个 block 返回来查看重现的行为:

[1,2,3].each {|x| return x } LocalJumpError: unexpected return from (irb):7 from (irb):7:in `each' from (irb):7

编辑:好的,我收回它,你可以从迭代器中返回。我的 LJE 是因为我在控制台(啊)。

编辑:好的,我明白你的问题了。基本问题是为什么 block[x]工作和yield x不是(假设 &block 是 lambda)。 看起来 yield x从 block 内联解释的代码并在数组迭代器的上下文中调用它,这将抛出 LJE(如上所述)和 block[x]不内联代码,仅从 block 本身返回。

因此,虽然未能回答您的问题,但我至少将其归纳为以下内容:

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 一样,并尝试从方法的上下文中返回。

关于ruby - 下面的 lambda 表达式如何抛出 LocalJumpError ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2221738/

相关文章:

ruby-on-rails - Rails 没有使用正确版本的 Ruby

ruby - 就地修改数组 - Ruby

c++ - Lambda 与排序函数

ruby-on-rails - rspec-mocks 'allow' 返回未定义的方法

java - 有没有办法比较 lambdas?

c# - 异步 lambda 的执行有什么区别吗?

ruby-on-rails - 在 Ruby 1.9 中使用 instance_eval 进行常量查找

ruby - enum#with_object 与 enum#each_with_object 有何不同?

ruby-on-rails - Rubygems 的 SSL 错误(无法连接)

ruby-on-rails - 部署后等待迁移