如果我有:
2.times do
i ||= 1
print "#{i} "
i += 1
print "#{i} "
end
我得到1 2 1 2了,而我却在期待1 2 2 3。为什么i循环重新开始时会丢失其分配?如果赋值发生在循环之外,它的行为与预期一样,所以我猜它与范围有关,但我没有意识到循环有自己的范围。有人可以澄清吗?
更新:感谢您对此的帮助。我的部分困惑源于从 Python 进入 Ruby,它没有块作用域(我认为)。
如果我有:
2.times do
i ||= 1
print "#{i} "
i += 1
print "#{i} "
end
我得到1 2 1 2了,而我却在期待1 2 2 3。为什么i循环重新开始时会丢失其分配?如果赋值发生在循环之外,它的行为与预期一样,所以我猜它与范围有关,但我没有意识到循环有自己的范围。有人可以澄清吗?
更新:感谢您对此的帮助。我的部分困惑源于从 Python 进入 Ruby,它没有块作用域(我认为)。
I don't know what your expectations are based on. If you think what I think you think, it should be 1 2 2 3. You can achieve that by declaring variable i outside of the block.
i = nil
2.times do
i ||= 1
print "#{i} "
i += 1
print "#{i} "
end
Then the block closes over that variable (closure) and uses it. Without closure, i is local to the block and is new every time.
看下面的代码:
2.times do
p defined? i
i ||= 1
p defined? i
p "#{i} "
i += 1
p "#{i} "
end
输出:
nil
"local-variable"
"1 "
"2 "
nil
"local-variable"
"1 "
"2 "
这意味着在每次迭代中都会创建一个新范围,并且i只有该范围知道;由nil和证明"local-variable"。
现在i在 之外创建block,并查看输出(没有 nil出现):
i = nil
2.times do
p defined? i
i ||= 1
p defined? i
p "#{i} "
i += 1
p "#{i} "
end
输出:
"local-variable"
"local-variable"
"1 "
"2 "
"local-variable"
"local-variable"
"2 "
"3 "
了解更多关于||=外观What Ruby’s ||= (Double Pipe / Or Equals) Really Does
具有范围的不是“循环”。是块。是的,块是本地范围。
如果您不希望将变量理解为块的本地变量,则它需要预先存在于块之外。即使只是i在前一行中设置为零也可以做到这一点。
(但您的期望1 2 3 4仍然无法满足......!)
你可以从中获得一些乐趣。例如,您想访问块内的范围。
block = -> do
x = "Hello from inside a block"
binding # return the binding
end
p defined? x #=> nil
x = eval "x", block.call #=> #<Binding:0x007fce799c7dc8>
p defined? x #=> "local-variable"
p x #=> "Hello from inside a block"
这很重要,因为它允许开发人员基本上摆脱对块的封装,应该谨慎使用。
简单的答案是您i在每次迭代时重新实例化变量并将其重置为 1。
Ruby 循环类似于x.times 创建本地范围,因此在此循环中引入的变量是本地的,并且将在到达块末尾后被销毁。这就是为什么您没有得到预期结果的原因。在 ruby 中,如果您想要没有本地范围的循环,您可以使用fororwhile不创建本地范围的循环,但您的本地变量i在循环后仍可访问。
for j in (1..2)
i ||= 1
print "#{i} "
i += 1
print "#{i} "
end
打印1 2 2 3为您的预期结果。现在,如果我们在循环老化之上运行,它将给出结果3 4 4 5。另一方面,对于额外的信息while和for工作相同(范围更少和打印),并且工作相同(创建本地范围和打印)1 2 2 3eachx.upto(y)x.times1 2 1 2