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的评估如下:
- 评估表达式 。 设
O
为结果值。设
E
是primary-expressionforms的主要 方法调用 [此处没有行终止符]。 每次执行| block-formal-argument-list | block-body end ,其中primary-expression的值为O
, block-formal-argument-list是for-variable , block-body是do-clause的复合语句 。评估
E
,但跳过§11.2.2的步骤c。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)。
- 升级到rails3后,after_find回调中断
- Rails,存储Google Client API的JSON凭据以及如何访问它的位置?
- 如何为包含“gets.chomp”的Ruby方法编写RSpec测试?
- capistrano – NameError:未初始化的常量Net :: SSH :: KnownHosts :: SUPPORTED_TYPE
- Rails:一个有2个域的应用程序 – 共享身份validation
- 如何通过坐标(使用WebDriver)单击canvas中的特定元素?
- 瘦身以阅读已配置的用户环境
- 过滤以从数组中排除元素
- void foo(int&x) – > Ruby? 通过引用传递整数?