第1回では,
今回は,
ブロックパラメータ (仮引数) に関する変更
ブロックパラメータのスコープがブロックローカルに
ブロック中の変数はスコープがやや曖昧でした。初出の変数の場合はブロックローカル
この問題を軽減するため,
コード1 ブロックパラメータがブロックローカルに
# ローカル変数xを定義する
x = "bear"
# ブロックローカル変数xを受け取るブロック(ローカル変数のxとは別!)
["dog", "cat", "panda"].each do |x|
# このブロックの中でxの参照はブロックローカル変数の方を指す
p x
break if x == "cat"
end
# ブロックを出るとxはローカル変数の方を指すようになる
p x
図1 コード1の実行結果
# 1.8で実行した場合 $ ruby18 block-param-scope.rb "dog" "cat" "cat" # 1.9で実行した場合 $ ruby19 block-param-scope.rb "dog" "cat" "bear"
これによって,
ただしこの変更には互換性の問題があります。つまり,
図2 -wつきでコード1を実行した結果
$ ruby19 -w block-param-scope.rb block-param-scope.rb:5: warning: shadowing outer local variable - x "dog" "cat" "bear"
また,
コード2 ブロックローカル変数の宣言
foo = "bear"
# ブロックローカル変数fooを宣言する
3.times do |x; foo|
# ブロックローカル変数fooは毎回nilで初期化される
p foo #=> nil
foo = "dog"
# ブロックの終了毎にブロックローカル変数fooは消える
end
# 外側のローカル変数は変更されない
p foo #=> "bear"
ブロックとメソッドの仮引数のルールが統一
ブロックの仮引数にオプショナル引数やrest引数
コード3 ブロック仮引数中でオプショナル引数が使える
def foo
yield 1, 2
yield 1
end
foo do |x, y = :default|
p [x, y]
end
図3 コード3の実行結果
[1, 2] [1, :default]
この機能はAPI設計の幅を広げると思います。また,
ただし,