lambda
Kernel.#lambda
もProcクラスのインスタンスを生成するメソッドです(lambdaはラムダと読みます)。生成されるオブジェクトはProcクラスのインスタンスですが、Procで作られたのかlambdaで作られたのかを区別するためにProc#lambda?
というメソッドが用意されています。
Ruby 1.9からは"lambda"の代わりに ->
という書き方(アロー記法)も使えるようになりました。アロー記法の場合は引数が -> {|x| ... }
ではなく -> (x) { ... }
となることに注意してください。
Procとlambdaの違い
Procとlambdaにはいくつかの違いがあり、おおまかに言うとlambdaの生成する手続きオブジェクトの方が、Procの生成する手続きオブジェクトに比べてメソッドに近い挙動をします。
- 引数の数に厳密なのがlambda、寛容なのがProc
- returnで自分自身から出るのがlambda、自分自身より上のメソッドをreturnするのがProc
lambdaの場合は引数の数(arity)が異なるとエラーになりますが、Procは足りない分をnilで埋め、余分な引数を捨てたうえで実行しています。
次にreturnの挙動です。
lambda内でreturnすると単にlambdaから出るだけで処理は続いており、Proc内でreturnしたときはwrap_proc
自体からもreturnされそこで処理が終わっていることがわかります。
クロージャ
最後にRubyから少し視野を広げて、計算機科学一般における「クロージャ」という概念でRubyのブロック、Proc、lambdaを眺めてみることにします。
クロージャ(closure) とは定義時のスコープにおける環境を保持し、その環境内でコードを実行することが出来るものです。なおここで言う「環境」とは「変数と変数の指すオブジェクトの集合」を指します。
Rubyにおいてクロージャと呼ぶことが出来るものは以下の3つです。
- ブロック
- Proc
- lambda
次のコード片は、ブロック、Proc、lambdaそれぞれの定義時に存在するローカル変数 「x
」 をスコープの内側から参照する単純な例です。
※メソッドは定義時の環境を参照できないためクロージャには含まれません。
以上
以上、Rubyを特徴付ける「ブロック」周辺について解説を行いました。
今回に限らず、本連載ではなるべく正確な情報を掲載するよう心掛けています。記事内容に誤りを発見された場合は著者に連絡頂くか、 allabout/021_block.md at master ? memerelics/allabout からプルリクエストを送って頂ければ反映いたします。