使用变量的当前值创建Proc

时间:2010-06-30 03:20:08

标签: ruby

我在库中没有创建的类中有一个讨厌的小函数问题(因此无法编辑)。这是一个简单的类,其中包含恼人的行为:

class Foo              # This is a class I cannot
  def setmyproc(&code) # safely edit.
    @prc = Proc.new    # Due to it being in a
  end                  # frustratingly complex
  def callmyproc()     # hierarchy, I don't
    @prc.call          # even know how to reopen
  end                  # it. Consider this class
end                    # set in stone.

当我尝试迭代并生成这些对象的数组时遇到问题。我期望用每个对象将一个不同的值替换为Proc i,但相反的是变量i在它们之间共享。

$bar = []
for i in (0..15)
  $bar[i] = Foo.new
  $bar[i].setmyproc { puts i }
end

$bar[3].callmyproc # expected to print 3
$bar[6].callmyproc # expected to print 6

输出

  15
  15

我可以在循环内做什么来为每个对象保留i的单独值?

3 个答案:

答案 0 :(得分:3)

使用此:

$bar = []
(0..15).each do |i|
  $bar[i] = Foo.new
  $bar[i].setmyproc { puts i }
end

$bar[3].callmyproc # prints 3
$bar[6].callmyproc # prints 6

如果您确实需要在循环内部进行更改,请使用此选项(仅限ruby 1.9):

$bar = []
for i in (0..15)
  ->(x) do
    $bar[x] = Foo.new
    $bar[x].setmyproc { puts x }
  end.(i)
end

$bar[3].callmyproc # prints 3
$bar[6].callmyproc # prints 6

答案 1 :(得分:2)

传递到$ bar数组中每个Foo的块绑定到同一个变量i。无论何时发送callmyproc,都会使用原始范围中i的当前值。

$bar[3].callmyproc
=> 15
$bar[6].callmyproc
=> 15

i = 42

$bar[3].callmyproc
=> 42
$bar[6].callmyproc
=> 42

您需要在每个过程中发送一个不同的对象:

0.upto(15) do |i|
  $bar[i] = Foo.new
  $bar[i].setmyproc { i.to_i }
end

$bar[3].callmyproc
 => 3 
$bar[6].callmyproc
 => 6 

答案 2 :(得分:1)

好的,首先,欢迎关闭:)

闭包是一段代码,你可以像变量一样传递,这是一个简单的部分。另一方面是闭包保持了调用它的范围。

实际发生的是,当你存储你的触发器时,每个触发器都会引用n。即使你超出了for循环的范围,对n的引用仍然存在,每次执行你的proc时,它们都会打印出n的最终值。这里的问题是每次迭代都不在自己的范围内。

Adrian建议做的是将for循环换成range.each块。不同之处在于每个迭代都有自己的范围,这就是与proc

绑定的内容
$bar = []
(0..15).each do |i|
  #each i in here is local for this block
  $bar[i] = Foo.new
  $bar[i].setmyproc { puts i }
end

这真的不是一件简单的事情,但它是其中一个会让你绊倒的东西,直到你真正得到它为止。我可能做了很糟糕的解释,如果它不凝胶我会花一点时间谷歌搜索闭包如何与范围一起工作。