Ruby scope,从函数返回一个Proc

问题描述:

来自JavaScript后台我已经习惯于能够使用JavaScript的动态范围来封装函数中的值。例如:Ruby scope,从函数返回一个Proc

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中是如何工作的一个快速的解释?如果我打电话给从give_me_a_proc返回的Proc,它是否仍然可以访问其定义范围?

同样,一旦我定义了proc,或者做了任何在Foo中做出的更改,即使在定义之后,这些值也会被固定下来。

在Ruby中,一个proc是一个闭包。在Javascript中,函数是闭包。关闭的想法是它“关闭”了它所定义的环境。在Ruby中,proc中的变量仍然可以改变,即使代码处于proc之外,新值也会反映在proc中(参见peakxu的演示)。不确定Javascript关闭是否以这种方式工作。

+0

谢谢,这正是我正在寻找的那种解释 – 2012-07-20 16:55:01

+0

欢迎。感谢您的反馈。你扔掉这些东西,你想知道它是否达到了标准。 :) – seph 2012-07-20 22:35:09

是的,它仍然可以访问定义时间范围。见documentation for Proc class

更改进行到Proc后定义。 irb的结果与你的班级一起运行。

> foo = Foo.new(1, 2) 
=> #<Foo:0x007f9002167080 @bar=1, @baz=2> 
> quux = foo.give_me_a_proc 
=> #<Proc:[email protected](irb):11> 
> quux.call 
=> 3 
> foo.bar = 3 
=> 3 
> quux.call 
=> 5 

Ruby procs和lambdas是关闭。当你做return Proc.new { @bar + @baz }你真的捕获了self,这是实例变量的查找方式。 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的值仍然可用。