14

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

示例案例:

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

输出:

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

如果您将food变量放在块内(每个块),我的理解是它具有块范围。它只存在于块范围内,对外部变量没有任何影响food

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

4

3 回答 3

13

这是 ruby​​ 1.8 的预期行为。它已在 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"]
于 2012-07-27T10:29:55.450 回答
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"foodfood

于 2012-07-27T10:50:54.897 回答
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"]
于 2013-02-18T07:02:32.243 回答