Ruby中的闭包和for循环

我是Ruby的新手,一些关闭逻辑让我很困惑。 考虑以下代码:

array = [] for i in (1..5) array < [5, 5, 5, 5, 5] 

这对我来说很有意义,因为我被绑定在循环之外,因此每次循环都会捕获相同的变量。 我也觉得使用每个块可以解决这个问题:

 array = [] (1..5).each{|i| array < [1, 2, 3, 4, 5] 

…因为我现在每次都被单独宣布。 但现在我迷路了:为什么我不能通过引入一个中间变量来修复它?

 array = [] for i in 1..5 j = i array < [5, 5, 5, 5, 5] 

因为j每次循环都是新的,我认为每次传递都会捕获一个不同的变量。 例如,这肯定是C#的工作原理,以及我认为 – Lisp的行为与let有关。 但在Ruby中并没有那么多。 真的发生了什么?

编辑:查看答案中的评论; 问题似乎是j仍然在循环之外的范围内。 循环中的范围如何真正起作用?

编辑:我想我还是不明白; if循环不创建新范围,为什么:

 for i in 1..5 puts j if i > 1 #undefined local variable or method `j' for main:Object (NameError) j = i end 

好的,这太荒谬了。 每当我尝试回答有关for循环如何在Ruby中工作的问题时,我就错了。

这样做的原因当然是我不在Ruby中使用for循环,其他人也没有,所以对我来说真的没关系:-)

无论如何,为了一劳永逸地解决这个问题,我直接找到了最终来源 ,即2009年12月1日的IPA Ruby语言规范初稿(注定要成为ISO Ruby语言规范):

§11.4.1.2.3表达式

句法

  • for-expression 表达式 do-clause 结束中的 for-variable
  • for-variable 左侧 | 多左手侧

for表达式的表达式不应是跳转表达式

语义

for-expression的评估如下:

  1. 评估表达式 。 设O为结果值。
  2. Eprimary-expressionforms的主要 方法调用 [此处没有行终止符]。 每次执行| block-formal-argument-list | block-body end ,其中primary-expression的值为Oblock-formal-argument-listfor-variableblock-bodydo-clause复合语句

    评估E ,但跳过§11.2.2的步骤c。

  3. for-expression的值是调用的结果值。

好吧,基本上这意味着

 for for_variable in expression do_clause end 

被翻译成

 O = expression O.each do |for_variable| do_clause end 

或者,在您的情况下:

 for i in 1..5 puts j if i > 1 #undefined local variable or method `j' (NameError) j = i end 

被翻译成

 (1..5).each do |i| puts j if i > 1 #no excpetion here, works just fine ??!!?? j = i end 

啊哈! 但我们忘记了什么! 这是一个不祥的“跳过§11.2.2的步骤c”。 事情! 那么,它说什么呢?

  • 将一组空的局部变量绑定推送到⟦local-variable-bindings⟧。

注意步骤b

  • 将执行上下文设置为E b

没有被跳过。

因此,据我所知, for循环获得了自己的执行上下文,它以当前执行上下文的副本开头,但它没有获得自己的局部变量绑定集。 IOW:它获得了自己的动态执行上下文,但没有自己的词法范围。

我必须承认,我仍然不确定我是否完全理解它,但它没有比这更精确。

你在运行这个版本的Ruby是什么版本的? 1.8没有局部变量的块范围,因此即使在for结束之后,j仍然会挂起(并且等于5)。