从另一个lambda调用lambda。为什么顺序很重要?

时间:2018-09-30 20:55:46

标签: ruby lambda scope

可以从另一个lambda调用lambda:

first   = -> { 'Ok' }
second  = -> { first.call }
puts second.call
# => 'Ok'

但是当顺序相反时:

first  = -> { second.call }
second = -> { 'Ok' }
puts first.call

代码失败,并显示NameError

lambda_order.rb:1:in `block in <main>': undefined local variable or method `second' for main:Object (NameError)
Did you mean?  send
    from lambda_order.rb:3:in `<main>'

即使:second似乎是first范围内的局部变量:

first  = -> { local_variables }
second = -> { 'Ok' }
p first.call
# => [:first, :second]

我只为golfing purposes使用lambda,所以我不确定范围是怎么回事。用方法或常量lambda替换second可修复NameError。似乎与此question有关,但就我而言,两个lambda都在main中定义。

你能解释一下吗?

2 个答案:

答案 0 :(得分:4)

创建lambda / proc时,其内容不会执行,但是在创建时,lambda / proc本身会绑定到当前作用域中的一组局部变量。

在您失败的示例中

first  = -> { second.call }
second = -> { 'Ok' }
puts first.call

由于在创建second lambda之前未定义first,因此变量不会作为first的{​​{3}}的一部分传递。

但是,只需在创建second之前定义first就可以解决此问题。

second = nil
first  = -> { second.call }
second = -> { 'Ok' }
puts first.call
# OK
#=> nil

Binding文档说:

  

创建一个绑定到当前上下文的新Proc对象。 Proc::new可能   仅在具有附加块的方法中不带块地调用,   在这种情况下,该块将转换为Proc对象。

将以上内容与Proc::new文档结合在一起。请记住,绑定是在创建时绑定到lambda / proc的(不是在调用时):

  

Binding的对象在某些地方封装了执行上下文   代码中的特定位置,并保留此上下文以供将来使用。   变量,方法,self的值,以及可能的迭代器块   在此上下文中可以访问的所有内容都将保留。绑定对象   可以使用Kernel#binding创建,并可供   Kernel#set_trace_func的回调。

我希望这可以使事情变得简单

答案 1 :(得分:4)

first  = -> { defined? second }
second = -> { 'Ok' }
p first.call

results nil =>在lambda“ first”中未定义变量“ second”。

first  = -> { binding.receiver }
second = -> { 'Ok' }
p first.call

result main =>这意味着它使用main的当前绑定,因此在binding中仅定义了变量“ second”。

first  = -> { binding.local_variable_get(:second).call }
second = -> { 'Ok' }
p first.call

结果为“确定”。这就是为什么当我要求绑定变量“ second”的内容时,代码还会显示“ Ok”的原因。

摘要:在lambda“ first”中未定义变量“ second”。变量“ second”仅在binding中定义。因此,“ local_variables”的输出也返回“ second”,因为该信息是从绑定中检索的。

我自己也学到了一些东西。希望我能为您服务!