エミュー

学んだことを書いていきます

ネストしたメソッドから外側の変数を参照したいができない(Ruby)

ダメな例

def twice(x)
  def inner(y)
    return x + y
  end
  return inner(x)
end
> twice(2)
NameError: undefined local variable or method `x' for main:Object

Rubyではdefしたらスコープが切り替わるため、defの外側のスコープを参照できない。
参考: Ruby のネストしたメソッドと、変数のスコープ | すぐに忘れる脳みそのためのメモ

解決策

def twice(x)
  inner = lambda {|y|
    return x + y
  }
  return inner.call(x)
end
> twice(2)
=> 4
> twice(3)
=> 6

ブロックをlambdaでオブジェクト化し、それをローカル変数に代入する。callメソッドで呼び出すときの引数がブロック変数に渡される。関数じゃないけど第一級関数みたいでおもしろい。
参考: 楽しいRuby第4版 p417-p420

innerはアローを使って次のようにも書ける

 inner = ->(y) {
    return x + y
  }

こっちは無名関数みたい。
参考: Matzにっき(2010-06-16)

まとめ

ネストしたメソッドはRubyではあまり意味がない。代わりにブロックを使う。