2012/03/04

Ruby1.9におけるローカル変数とブロック変数の関係

Ruby1.9からブロック内の変数のスコープが変わったようなのでメモ。


1.9ではブロック変数はブロックローカル変数として扱われる

つまり、ブロック内のパラメータとして定義された変数のスコープはブロック内に限定される、ということ。これをブロックローカル変数という。
試しに下記のコードを1.8.7、1.9.3それぞれのバージョンで実行してみる。

block_test.rb
x = 1
ary = [1,2,3]

ary.each do |x|
  puts x
end

p x

1.8.7での実行結果
$ ruby block_test.rb
1
2
3
3
1.9.3での実行結果
$ ruby block_test.rb
1
2
3
1
上記のように、1.8.7では最初に定義したx=1がイテレータ実行による影響を受けて x=3 になっているが、1.9.3では x=1 が保持されている。


ブロックパラメータで指定していない変数はブロックローカルにはならない

ブロック内でパラメータとして定義されずに利用された変数はブロックローカルな変数ではないため、ローカル変数として扱われる。

例えば、
x = 1
ary = [1,2,3]

ary.each do |y|
  x = y
end

p x
とすると結果は x=3 になる。念のため。
また、上記のようなケースで x もブロックローカルにするためには下記のように記述する。
x = 1
ary = [1,2,3]

ary.each do |y; x|
  x = y
end

p x
上記の実行結果は x=1 になる。


<以下、2012/03/05追記>

もうちょっと複雑にしてみると、
x = y = z =0         # 変数初期化
ary = [1, 2, 3]

ary.each do |x; y|   # 配列の要素はxに順番に代入される。yはブロック内のみをスコープとしたブロックローカル変数
  y = x              # ブロック変数xに配列の要素が順番に追加され、ブロックローカル変数yに代入される
  z = x              # ブロック変数xに配列の要素が順番に追加され、ローカル変数zに代入される
  p [x, y, z]
end

p [x, y, z]

実行結果は下記のようになる。
[1, 1, 1]
[2, 2, 2]
[3, 3, 3]
[0, 0, 3]

ブロックローカル変数として定義をしなかったzのみ影響を受けていることがわかる。



参考サイト

Ruby 1.9に移行する際に注意すべき10のポイント - なんとなく日記


0 件のコメント:

コメントを投稿