Ruby の "shadowing outer local variable" という警告について


ブロックパラメータを指定する際は, ローカル変数と同じ名前ではないか気をつける必要があります.

例えば次のような Ruby コードがあります:

# example.rb

n = 0
arr = [1, 2, 3]
arr.each do |n|
  n *= 2
  puts n
end

puts "Local variable n: #{n}"

そしてそれを ruby -w で警告があれば表示するという設定で実行すると:

ruby -w example.rb

このような警告が発せられます:

example.rb:5: warning: shadowing outer local variable - n
2
4
6
Local variable n: 0

これはどういうことかと言いますと example.rb の 5 行目:

arr.each do |n|

のブロックパラメータの n が 3 行目:

n = 0

n を見えなくしてしまって, その元々の 3 行目の n をブロック内で参照することができなくなってしまったという内容の警告です.

また Local variable n: 0 という結果を見てもわかるように, ブロックパラメータでローカル変数と同じ名前の n を使用したからといって, 元々のローカル変数 nn *= 2 による代入によって上書きされるということはありません.

もし上書きされていれば, Local variable n: 0 という結果ではなく Local variable n: 6 となっていたはずです.

なので shadowing (影で覆う) という警告になるわけです.

修正方法

このようにエラーではないのですが, 警告ということなので直してあげる必要があります .

その場合, ローカル変数 n, もしくはブロックパラメータ n のどちらかを別の名前に変更する必要があります.

なので次のような二通りの修正方法があります:

  1. ローカル変数 n を別の名前に変更する:

    num = 0
    arr = [1, 2, 3]
    arr.each do |n|
      n *= 2
      puts n
    end
    
    puts "Local variable num: #{num}"
    
  2. ブロックパラメータ n を別の名前に変更する:

    n = 0
    arr = [1, 2, 3]
    arr.each do |num|
      num *= 2
      puts num
    end
    
    puts "Local variable n: #{n}"
    

まとめ

プロックパラメータを指定する時は, ブロックの外側のローカル変数と名前が同じにならないか注意する必要があります.

また同じになってしまってもどちらかの変数名を変えてあげればいいので, 比較的簡単に修正できます.

ただエラーではなく警告なので, ruby -w を実行するまで気づけなかったということがあるかもしれません.

なので使用しているエディタがそのような警告を出してくれる機能が付いているといいのでしょう.

僕は Vim を使っているので Syntastic というリンターのプラグインにお世話になっています.

Vim を使われている方は Syntastic はおすすめです.

最後までお読みくださいましてありがとうございました.