如果我有:
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 中,如果您想要没有本地范围的循环,您可以使用for
orwhile
不创建本地范围的循环,但您的本地变量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 3
each
x.upto(y)
x.times
1 2 1 2