在ruby中我们有一个迭代器,我在some blog中读到了
传递给迭代器的块中声明的变量(例如,
times
或each
)在每次迭代的顶部未定义!
所以当我尝试执行
时3.times do |loop_num|
sum ||= 0
sum += 1
puts sum
end
它给我输出
1
1
1
[Finished in 1.1s]
如果我对for循环
做同样的事情for loop_num in 1..3
sum ||= 0
sum += 1
puts sum
end
输出
1
2
3
[Finished in 0.2s]
但现在当我再次执行时间迭代器时,它将输出为
4
5
6
[Finished in 0.2s]
所以任何人都可以解释这种行为,为什么它不是将总和赋值为0而是将其值设为3(这是为for循环中赋值为sum的最后一个值)并将结果赋予为4 5 6
答案 0 :(得分:2)
您看到此行为的原因是因为3.times
正在执行块,而for .. in
循环正在其调用的相同上下文中执行。这就是闭包发挥作用的地方。
在您的第一个示例中,sum
尚未在块可以访问它的任何位置定义。因此,每次执行块时都会重新定义sum
。如果您在阻止后添加puts sum
语句,则会看到sum
未定义。
对于for循环示例,您将保持在相同的上下文中,因此第二次通过循环sum
已经在上下文中定义,因此它使用现有值。您可以通过在循环后添加puts sum
语句来验证这一点,您将看到它具有在循环中设置的最后一个值。
在执行循环后执行3.times
块时,闭包中存在sum
,因此块使用已定义的变量,而不是每次循环时重新定义它。 / p>
答案 1 :(得分:2)
这是某种程度的预期。根据{{3}} :(强调添加)
for
循环类似于使用each
,但不会创建新的变量范围。
在Ruby中,常规方法(如documentation,times
或each
)会创建新的变量范围,而loop
则会for
,while
}或until
没有。
因此,这段代码:
for loop_num in 1..3
sum ||= 0
sum += 1
puts sum
end
3.times do
sum ||= 0
sum += 1
puts sum
end
相当于:
sum ||= 0
sum += 1
puts sum
sum ||= 0
sum += 1
puts sum
sum ||= 0
sum += 1
puts sum
3.times do
sum ||= 0
sum += 1
puts sum
end
答案 2 :(得分:1)
根据@ rdubya的回答,你误解了博客文章的引用。
帖子的含义是在此代码块中:
3.times do |t|
puts defined?(var_only_in_block) ? true : false
var_only_in_block = 1
end
# false
# false
# false
每次迭代在运行后销毁变量var_only_in_block
,这使得它在下一次迭代开始时未定义。
但是,块可以访问定义范围内的变量。举个例子:
var_outside_block = 1
3.times do |t|
var_outside_block += 1
puts var_outside_block
end
# => 2
# => 3
# => 4
因为变量是在块之外定义的,所以在每次迭代期间所做的更改都会被保留。