Ruby作用域,从函数返回Proc

Ruby scope, returning a Proc from a function

本文关键字:返回 Proc 函数 作用域 Ruby      更新时间:2023-12-23

来自JavaScript背景,我已经习惯了使用JavaScript的动态范围将值封装在函数中。例如:

function Dog( firstname, lastname ) {
  this.fullname = firstname + lastname
  return {
    say_name: function () {
      return fullname;
    }
  }
}

现在在Ruby中,我不太确定这样的东西会不会工作得太好:

class Foo
  attr_accessor :bar, :baz
  def initialize bar, baz
    @bar = bar
    @baz = baz
  end
  def give_me_a_proc
    return Proc.new { @bar + @baz }
  end
end

有人能快速解释一下Ruby中scope是如何工作的吗?如果我调用从give_me_a_proc返回的Proc,它还会访问其定义的时间范围吗?

此外,一旦我定义了proc,这些值是否会变为固定值,或者在Foo中所做的任何更改是否会在定义后结转到proc?

是的,它仍然可以访问定义时间范围。请参阅Proc类的文档。

更改将转入Proc post定义。irb的结果与你的班级一起运行。

> foo = Foo.new(1, 2)
 => #<Foo:0x007f9002167080 @bar=1, @baz=2> 
> quux = foo.give_me_a_proc
 => #<Proc:0x007f900214f688@(irb):11> 
> quux.call
 => 3 
> foo.bar = 3
 => 3 
> quux.call
 => 5 
在Ruby中,proc是一个闭包。在Javascript中,函数是一个闭包。闭包的概念是,它"封闭"了定义它的环境。在Ruby中,proc中的变量仍然可以更改,即使是在proc之外的代码也可以更改,并且新值将反映在proc中(见peakxu演示)。不确定Javascript闭包是否以这种方式工作。

Ruby procs和lambdas是闭包。当您执行return Proc.new { @bar + @baz }时,您实际上是在捕获self,这就是查找实例变量的方式。Ruby块也是闭包。Ruby确实允许您更改变量,并且这些更改将传播到调用范围,假设调用范围仍然存在:

@hi = 0
def get_hi()
  lambda {@hi = 42}
end
get_hi.call()
@hi #=> 42

注意:除非您的proc有非常宽松的参数要求(它不在乎是否有任何参数,有多少,有点像C的int f(void)),否则使用lambda而不是Proc.newlambda检查以确保获得正确数量的参数。

Ruby有一个从对象获取闭包的方法,它非常适合您的示例:

class Foo
  # reopen Foo class
  def get_sum
    @bar + @baz
  end
end
m = Foo.new(5,20).method(:get_sum)
m.call #=> 25

mMethod对象,它在Foo的实例中充当闭包,因此实例变量和self的值仍然可用。