突然ですが、みなさんは「RubyのProcオブジェクト」についてしっかり理解できているでしょうか?
Rubyには、ブロックというものがあります。Procと似ていますが、少し違います。またブロックやProcを調べていると、yieldという言葉を見かけるかもしれません。
yieldもブロックやProcと関連のある言葉と言えるかもしれませんが、「yieldって何?」と説明を求められたら、悩んでしまいませんか?
私は以前、yieldの知識が曖昧だったために、問題を解決するのに時間を要してしまったことがあります。
Rubyを勉強し始めた方にとっては、分類が難しく全体像を捉えにくい概念だと思うので、一つ一つ整理していこうと思います。
初級者以上の方でも、「曖昧な理解だな」と思う方はこの機会に押さえておきましょう。
以下、ブロック・Proc・yieldの順でまとめていきます。
目次
ブロック
ブロックとは何か?
「RubyのProcオブジェクトとは?」という題名なので、Procオブジェクトの説明に入ると思いきや、最初は「ブロック」について説明していこうと思います。
Rubyのブロックというのは、「do ~ end」または「{ ~ }」と書かれるものです。「~」部分に敵数を読み込ませて色々な処理をすることができます。また、ブロックはオブジェクトではないというのもポイントです。
ブロックの使用例
上のプログラム例のようにブロックは、「do ~ end」で囲むパターンと「{ ~ }」で囲むパターンがあります。
加えて、例の「| f |」という部分はブロック変数と呼ばれます。ブロック変数はメソッドから渡されたパラメータです。
Proc
Procとは何か?
ブロックを説明したところで、Procの説明に移ります。先ほどブロックはオブジェクトではないと示しました。
Rubyはオブジェクト指向なので、全てオブジェクトとして捉えられると何かと便利なので、ブロックもオブジェクト化したい。
というよりも、オブジェクト指向なのでオブジェクトにしないと存在できないのです。
つまりProcというのは、「ブロックをオブジェクト化」したものということになります。
Procの使用例
Procは上記のように作り、実行することができます。
呼び出して実行する時は「callメソッド」を使います。
またメソッドにブロックを渡す時に引数として「&引数名」とすると、Procオブジェクトになりメソッドの中でブロックを使うことができます。
メソッド内で、「引数名.call」とするとProcオブジェクトが呼ばれ実行することができます。
yield
yieldとは何か?
yieldを言葉だけで伝えようとすると、わかりにくくなってしまうのですが、まとめておこうと思います。
yieldはメソッドの中で使われる時、メソッドの呼び出しと一緒に定義されたブロックをProcオブジェクトにしてProcを実行することができるものです。
やはり言葉だけでは、わかりにくかったと思うので、実際にyieldのプログラム例を見て理解してみましょう。
yieldの使用例
yieldの使用例は、どのようにyieldのみでProcが呼び出され実行できるようになるか、段階に分けて説明していきます。
まずyieldを使わない時は、第一段階の処理になります。Procの説明の時に記した通りです。
それを第二段階で、「引数名.call」という部分をyieldに置き換えています。なぜなら「&引数名」は、一つしか定義できないからです。そのため、「Procオブジェクト=yieldで呼び出せる」としてしまった方が「引数名.call」と書くより効率的だったのです。
第三段階では、ついに「&引数名」という記述も無くなってしまいました。「yieldがあるということはProcが呼び出されて実行されるんだな」という暗黙の了解で、yieldのみでProcオブジェクトを実行できるようになりました。
このような経緯があり、今日では第三段階の書き方でメソッドにブロックが渡されるようになったのです。
まとめ
今回は、ブロック・Procオブジェクト・yieldなど同じような概念について整理し説明してきたわけですが、いかがだったでしょうか?
これまで、曖昧にブロックを実行していた方やこれからプログラミングをしていく中でブロックやprocなどを使ってく方、そんな方々お役に立てたのなら幸いです。
プログラミング言語の書き方には、色々な経緯があって今の書き方になっているということを意識した方がいいと思います。
今回はyieldがそうでしたが、経緯を知っている人には短くて良いコードなのですが、知らない人にとったら理解に苦しむコードです。そんな時上のことを意識することで、コードを理解することの突破口が開けると思います。
コメントを残す