如果我有:
2.times do
i ||= 1
print "#{i} "
i += 1
print "#{i} "
end
我得到1 2 1 2
,而我期待1 2 2 3
。为什么i
在循环重新开始时会丢失它的赋值?如果赋值发生在循环之外,它的行为与预期一致,所以我猜它与范围有关,但我没有意识到循环有自己的范围。有人可以澄清吗?
更新:感谢您的帮助。我的一些困惑源于从Python进入Ruby,它没有块范围(我认为)。
答案 0 :(得分:10)
我不知道你的期望是基于什么的。如果你认为我认为你的想法,它应该是1 2 2 3
。您可以通过在块外声明变量i
来实现此目的。
i = nil
2.times do
i ||= 1
print "#{i} "
i += 1
print "#{i} "
end
然后该块关闭该变量(闭包)并使用它。没有闭包,i
是块的本地,每次都是新的。
答案 1 :(得分:9)
请看下面的代码:
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
答案 2 :(得分:3)
不是具有范围的“循环”。这是块。是的,块是本地范围。
如果您不希望变量被理解为块的本地变量,则需要事先在外部块中存在。即使只是在前一行中将i
设置为nil也可以这样做。
(但你对1 2 3 4
的期望仍然不会得到满足......!)
答案 3 :(得分:2)
你可以玩得开心。比如说你想访问块内的范围。
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"
这很重要,因为它允许开发人员基本上吹掉块的封装,应该谨慎使用。
答案 4 :(得分:1)
简单的答案是您在每次迭代时重新定义变量i
并重置为值1。