Rubyにおけるローカル変数のスコープ

いまさらだけど、あれ?と思うことがあったのでメモ。

変数と定数 (Ruby 2.6.0)

「ローカル変数のスコープは、宣言した位置からその変数が宣言されたブロック、メソッド定義、またはクラス/モジュール定義の終りまでです。」

試してみる。

top_level = 1

class Klass
  in_class = 1
  
  def method
    in_method = 1
    
    [0].each do
      in_block = 1
      
      p defined?(top_level)   # => nil
      p defined?(in_class)    # => nil
      p defined?(in_method)   # => "local-variable"  # これはつかえるのか!
      p defined?(in_block)    # => "local-variable"
    end
    
    p defined?(top_level)   # => nil
    p defined?(in_class)    # => nil
    p defined?(in_method)   # => "local-variable"
    p defined?(in_block)    # => nil
  end
  
  p defined?(top_level)   # => nil
  p defined?(in_class)    # => "local-variable"
  p defined?(in_method)   # => nil
  p defined?(in_block)    # => nil
end

p defined?(top_level)   # => "local-variable"
p defined?(in_class)    # => nil
p defined?(in_method)   # => nil
p defined?(in_block)    # => nil
  • ローカル変数は宣言されたスコープの外側ではつかえない。上記の例でいうと…

    • クラス内で宣言されたローカル変数は、そのクラスの外側ではつかえない。
    • メソッド内で宣言されたローカル変数は、そのメソッドの外側ではつかえない。
    • ブロック内で宣言されたローカル変数は、そのブロックの外側ではつかえない。
  • ローカル変数は宣言されたスコープの配下にある独立したスコープでは(基本的に)つかえない。上記の例でいうと…

    • トップレベルで宣言されたローカル変数は、その配下にあるクラスの中ではつかえない。
    • クラス内で宣言されたローカル変数は、その配下にあるメソッドの中ではつかえない。
    • ただし!!!
    • ある場所で宣言されたローカル変数は、その直下のブロック内でつかうことができる!!!
    • 上記の例では、メソッド内で宣言したローカル変数が、その配下にあるブロックの中でつかえている。

トップレベル/クラス/ブロック内でローカル変数を宣言した場合も同様に、直下のブロックの中でつかうことができる。

# トップレベルの場合
top_level = 1

[0].each do
  p defined?(top_level)  # => "local-variable"
end

# クラスの場合
class Klass
  in_class = 1
  
  [0].each do
    p defined?(in_class)  # => "local-variable"
  end
end

# ブロックの場合
[0].each do
  in_block = 1
  
  [0].each do
    p defined?(in_block)  # => "local-variable"
  end
end

ふーん例外的な動きをするんだなー、と思ったのだが、「いやいや、例外ではなくこういう観点からみれば当然のこと」みたいなのがあればすごく教えてほしいです。