hasciiの日記

多分プログラミング関係

ruby のブロック内の変数とif文とのスコープ的なアレ

ruby のブロック内の変数とメソッド内の
スコープ的なもののメモ (ruby 1.8.7 で実行)


復習

def dummy
  yield
end

def func
  foo = nil
  dummy{foo = :hoge}
  foo
end

func # => :hoge

def func
  dummy{foo = :hoge}
  foo
end

func # => NameError: undefined local variable or method `foo' for main:Object

ここまでは問題無いと思う。
で、↓こんなコードがあったとき、

def dummy
  yield
end

def func(arg)
  if arg
    foo = :foo1
  else
    dummy { foo = :foo2}
  end
  foo
end

func(nil) だとどうなるか気になったので実行してみた。

func(true) # => :foo1
func(nil)  # => :foo2

arg = nil のときのブロックの中の foo は外の foo になるらしい、
多分 if の中を先に評価して名前空間内に foo が出てくるんだと思う。


じゃあこんなの↓ならどうなる?

def func(arg)
  unless arg
    dummy{ foo = :foo3}
  else
    foo = :foo4
  end
  foo
end
func(true) # => :foo4

これは期待通り

func(nil) # => nil

上から見て先に出ないとブロック内の変数になる(その後のelse 内で出てくるから、NameError にはならない)。
この例ぐらい分かりやすい話なら気付くけど、複雑なコードだと面倒なバグの原因になるかもねー

おまけ

def func
  eval("foo = :foo5")
  foo
end
func # => NameError: undefined local variable or method `foo' for main:Object

def func
  foo = nil
  eval("foo = :foo6")
  foo
end
func # => :foo6