14

私の理解では、ルビブロックにはブロックスコープがあり、ブロック内で作成されたすべての変数はブロック内にのみ存在します。

例:

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

出力:

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

foodブロック内 (各ブロック)の変数を使用する場合、私の理解では、ブロック スコープがあるということでした。これはブロック スコープ内にのみ存在し、外部変数には影響しませんfood

ただし、動作は異なりますfood。この場合、指定された外部変数が変更されます。この理解は正しいですか、ruby にはブロック スコープがありますか?

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 に答える