在ruby中阻止范围

时间:2012-07-27 10:26:19

标签: ruby scope variable-assignment block

我的理解是ruby块具有块范围,并且块内创建的所有变量将仅在块内生存。

示例案例:

 food = ['toast', 'cheese', 'wine']
 food.each { |food| puts food.capitalize}
 puts food

输出:

"Toast"
"Cheese"
"Wine"
"Wine"

如果你在块(每个块)中取food变量,我的理解是它有块范围。它仅存在于块范围内,并且对外部变量food没有任何影响。

但行为不同,在这种情况下修改了名为food的外部变量。这种理解是否正确,在ruby中我们是否有块范围?

3 个答案:

答案 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"]