在Ruby方法中捕获变量

时间:2013-08-02 23:14:23

标签: javascript ruby coffeescript closures

在CoffeeScript中:

f = ->
  v = 5
  g = ->
    v
  g()

f() # returns 5 as expected

在Ruby中:

def f
  v = 5
  def g
    v # undefined local variable or method `v' for main:Object (NameError)
  end
  g
end
f

好的,显然JavaScript函数被设置为捕获创建它们的范围中的变量,但Ruby的方法不是。有没有办法让Ruby方法在这方面像JavaScript函数一样?

5 个答案:

答案 0 :(得分:8)

您并没有真正在Ruby中定义方法内部的方法,但您可以使用lambda

def f
  v = 5

  g = lambda do
    v
  end

  g.call
end

答案 1 :(得分:7)

Ruby具有脚本范围,模块/类/方法定义范围和块范围。只有块创建嵌套范围。因此,您需要使用块来定义方法。值得庆幸的是,有一种方法可以定义采用块的方法:

def f
  v = 5
  define_method :g do
    v
  end
  g
end
f
# => 5

但是,请注意,执行您认为的操作(原始代码也不行)。它定义嵌套在方法g中的方法f。 Ruby没有嵌套方法。方法总是属于模块(类是模块),它们不属于方法。

这样做是定义一个方法f,当你运行它时定义一个方法g,然后调用该方法。

观察:

methods.include?(:g)
# => true

您现在已经定义了一个名为Object的新顶级方法(实际上是g的私有实例方法),并且您将每次{{1}一次又一次地定义它。被调用。

你可能想要的是一个lambda:

f

在对另一个答案的评论中写道:

  

好的,所以我正在搞乱lambdas,我注意到def f v = 5 g = -> { v } g.() end f # => 5 vg v所做的任何事情都没有反映在g 。有没有办法可以对v粘贴进行更改?

def f
  v = 5
  g = -> { v = 'Hello' }
  g.()
  v
end
f
# => 'Hello'

正如您所看到的,v返回后,对g 的更改“坚持”。

答案 2 :(得分:2)

简短的回答,没有。 Ruby的函数具有与Javascript函数不同的作用域规则。

更长的答案是您可以在Ruby中定义对象,以保留定义它们的范围(称为闭包)。这些在Ruby中称为lambdas,Procs和块。查看here以获得快速概述。

编辑:块不是Ruby对象,但可以将它们转换为Procs,它们是对象。

答案 3 :(得分:1)

要添加其他答案,与CoffeeScript代码最为一致,您可能会写:

f = lambda do
  v = 5

  g = lambda do
    v
  end

  g[]
end
f[]

答案 4 :(得分:1)

闭包是一个命名的代码块(某些语言中的函数,Ruby中的lambda或proc),具有以下特征:

  • 它会记住所有可用变量的值 它被定义的范围(外部范围),即使在另一个范围上调用时也是如此 或者当这些变量不再可用时(超出范围)。
  • 这是一个对象。因此,它可以分配给变量,传递,从不同范围内调用等等。

以下是使用Lambda的示例。使用Proc。

可以完成同样的工作
minutes = 40
def meditate minutes
    return lambda { minutes }
end

p = meditate minutes
minutes = nil
p.call

# Output:
=> 40

注意lambda是在meditate方法中创建的,它花了几分钟作为参数。后来,当我们打电话给lambda时,冥想方法已经消失了。我们还将分钟值设置为零。尽管如此,lambda还记得"分钟"的价值。

Ruby有两种类型的闭包:Lambdas和Procs。

方法不是闭包,Method对象也不是。正如Yukihiro Matsumoto(Matz)在他的书“The Ruby Programming Language:

”中所说
  

Method对象和Proc对象之间的一个重要区别是Method对象不是闭包。 Ruby的方法旨在完全自包含,并且它们永远不能访问其范围之外的局部变量。因此,Method对象保留的唯一绑定是self的值 - 调用该方法的对象。

this post about Methods in the Zen Ruby blog.

了解详情