ruby

时间:2017-01-06 11:09:26

标签: ruby

在ruby中我们有一个迭代器,我在some blog中读到了

  

传递给迭代器的块中声明的变量(例如,timeseach)在每次迭代的顶部未定义!

所以当我尝试执行

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

3 个答案:

答案 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中,常规方法(如documentationtimeseach)会创建新的变量范围,而loop则会forwhile }或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

因为变量是在块之外定义的,所以在每次迭代期间所做的更改都会被保留。