Monday, 26 November 2012

Ruby block, Proc, lambdaについてやっと調べてみました。

ずっと分からないと感じていたRubyのclosureについて調べてみました。

まずProcオブジェクトは手続きを記述したコードブロックを保存したオブジェクトです。これだけだとただの無名関数ですが、Procはその中にその時の周りの変数の状態なども保存できる事から、closureになるのでしょう(PHPのある日本語マニュアルページでは”無名関数はクロージャとも呼ばれ”と書いてあるけど…)。

例えば

x = 0

foo = Proc.new {return x}
foo.call

とすると

=>0

が返ってきます。しかし、


foo = Proc.new {return x}
x = 0
foo.call

とすると

NameError: undefined local variable or method `x' for main:Object

とエラーが出ます。Proc.newした時にあったKernelにくっついたxメソッドの返り値を参照しているのでしょう。ここで => 0が返って来ないのがclosureと無名関数の違いなのではないでしょうか?

Rubyでは変数の明示的削除はできないらしいですが、例えば


x = 0

foo = Proc.new {return x}
x.delete
x = 0
foo.call


などとできると

NameError: undefined local variable or method `x' for main:Object

のエラーが返ってくると思います。


closureの使い途として考えられるのは例えばDBにクエリを送る際にメソッドチェーンにして遅延評価し、DBのIOを少なくする事でしょうか。

例えばPostモデルがあった時に

@post = Post.has_image.sort_by_date.first

そのままコードを読めば、has_imageメソッドでまずPostのオブジェクトの配列を作って取得し、その後でソートして、その一番最初のオブジェクトを取得するとなります。が、本当にこんな事をしていればサービスとして破綻してしまいますね(破綻しなくても無駄が多すぎて許せないという人もいるのでしょうか…)。

ここはActiveRecordやその他のORMではProcを使用してsort_by_dateの部分までクエリを作ってしまってfirstで初めてPostのオブジェクトを返すという事にしているのでは(まだActiveRecordのコードは読んだ事が無いのですが、これは次の課題です)?

誰かこの文を読んでclosure理解の役に立つと良いですね…。それともやっぱり分かりにくい文になったかな…。

No comments:

Post a Comment