我的理解是ruby块具有块范围,并且块内创建的所有变量将仅在块内生存。
示例案例:
food = ['toast', 'cheese', 'wine']
food.each { |food| puts food.capitalize}
puts food
输出:
"Toast"
"Cheese"
"Wine"
"Wine"
如果你在块(每个块)中取food
变量,我的理解是它有块范围。它仅存在于块范围内,并且对外部变量food
没有任何影响。
但行为不同,在这种情况下修改了名为food
的外部变量。这种理解是否正确,在ruby中我们是否有块范围?
答案 0 :(得分:13)
这是ruby 1.8的预期行为。 It was fixed in 1.9。下面的片段使用ruby 1.9.3
运行food = ['toast', 'cheese', 'wine']
food.each { |food| puts food.capitalize.inspect} # !> shadowing outer local variable - food
puts food.inspect
# >> "Toast"
# >> "Cheese"
# >> "Wine"
# >> ["toast", "cheese", "wine"]
您是正确的,来自块的food
范围限定为该块并使用此名称隐藏其他变量。但是如果你做了一些破坏性的东西,它会反映在原始数组中,因为它是对数组元素的引用,而不是它的副本。观察:
food = ['toast', 'cheese', 'wine']
food.each { |f| f.capitalize} # transform and discard
food # => ["toast", "cheese", "wine"]
food.each { |f| f.capitalize! } # transform destructively (bang-version)
food # => ["Toast", "Cheese", "Wine"]
答案 1 :(得分:4)
块从其定义的上下文继承范围。看一下这个例子:
def give_me_a_proc
test = "foo"
lambda { puts test }
end
test = "bar"
give_me_a_proc.call
# => "foo"
所以proc / block的执行位置无关紧要,而是定义它的位置。
在您的情况下,块内的food
变量确实从外部遮蔽了food
数组。但是你真的对块中food
数组的实际元素(不是重复/克隆)进行操作,因此对它们的任何更改都将反映在外部。
块完成后food
数组变为"Wine"
字符串的原因是该块在定义food
数组的相同范围内运行,因此它将覆盖它数组的最后一个元素,因为它是分配给food
变量的最后一个对象。
答案 2 :(得分:1)
此漏洞已在Ruby 1.9中修复
food = ['toast', 'cheese', 'wine']
food.each { |food| puts food.capitalize }
puts food # ["toast", "cheese", "wine"]
我想如果你想在Ruby 1.8中使用局部变量,试试lambda
(对不起,我不安装Ruby 1.8,所以不能测试它,但是在1.9中工作)
food = ['toast', 'cheese', 'wine']
lambda do |food|
food.each {|food| puts food.capitalize}
end.call(food)
puts food # ["toast", "cheese", "wine"]