gpt4 book ai didi

ruby - Ruby 中的闭包和 for 循环

转载 作者:数据小太阳 更新时间:2023-10-29 07:12:28 27 4
gpt4 key购买 nike

我是 Ruby 的新手,有些闭包逻辑让我感到困惑。考虑这段代码:

array = []
for i in (1..5)
array << lambda {i}
end
array.map{|f| f.call} # => [5, 5, 5, 5, 5]

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

array = []
(1..5).each{|i| array << lambda {i}}
array.map{|f| f.call} # => [1, 2, 3, 4, 5]

...因为现在每次通过时都单独声明 i。但现在我迷路了:为什么我不能通过引入一个中间变量来修复它?

array = []
for i in 1..5
j = i
array << lambda {j}
end
array.map{|f| f.call} # => [5, 5, 5, 5, 5]

因为 j 每次循环都是新的,我认为每次循环都会捕获不同的变量。例如,这绝对是 C# 的工作方式,以及——我认为——Lisp 使用 let 的方式。但在 Ruby 中不是那么多。到底发生了什么?

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

编辑:我想我还是不明白;如果循环不创建新的作用域,为什么会这样:

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 循环,其他人也没有,所以这对我来说真的无关紧要:-)

总之,为了一劳永逸地解决这个问题,我直接去了the ultimate source , 2009 年 12 月 1 日 IPA Ruby 语言规范初稿(即将成为 ISO Ruby 语言规范):

§11.4.1.2.3 The for expression

Syntax

  • for-expression for for-variable in expression do-clause end
  • for-variable left-hand-side | multiple-left-hand-side

The expression of a for-expression shall not be a jump-expression.

Semantics

A for-expression is evaluated as follows:

  1. Evaluate the expression. Let O be the resulting value.
  2. Let E be the primary-method-invocation of the form primary-expression [no line-terminator here].each do | block-formal-argument-list | block-body end, where the value of the primary-expression is O,the block-formal-argument-list is the for-variable, the block-body is the compound-statement of the do-clause.

    Evaluate E, but skip Step c of §11.2.2.

  3. The value of the for-expression is the resulting value of the invocation.

好的,所以基本上这意味着

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”。事物!那么,它说了什么?

  • Push an empty set of local variable bindings onto ⟦local-variable-bindings⟧.

注意步骤b

  • Set the execution context to Eb.

没有被跳过。

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

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

关于ruby - Ruby 中的闭包和 for 循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2831470/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com