Ruby で クロージャ を実装する(Proc オブジェクト を用いる)

クロージャ とは

Wikipedia で「クロージャ」を見てみます。

ja.wikipedia.org

クロージャ(クロージャー、英語: closure)、関数閉包はプログラミング言語における関数オブジェクトの一種。いくつかの言語ではラムダ式や無名関数にて利用可能な機能・概念である。引数以外の変数を実行時の環境ではなく、自身が定義された環境(静的スコープ)において解決することを特徴とする。関数とそれを評価する環境のペアであるともいえる。

何を言っているのかさっぱり分かりません*1。具体的にコードを書いて理解をしてみました。言語は Ruby です。

Ruby で クロージャ を実装する

Proc オブジェクトを用います。Proc オブジェクトとは、ブロックをオブジェクト化したものです。詳細は別に譲ります。

クロージャを実装するので、「戻り値が Proc オブジェクト であるメソッド(関数)」を作ることが必須となります。そのメソッド(関数)を適当な変数に代入し、戻り値である Proc オブジェクト を、 call メソッドを用いて実行する、という流れです。

その前提のもと、以下に「クロージャにならない例」と「クロージャになる例」を順に書きます。

クロージャにならない例

クロージャにならない例です。

def this_is_not_closure
  Proc.new do
    i = 0

    i += 1
  end
end

上記のように定義した this_is_not_closure をクロージャであると仮定して、実行してみます。

foobar = this_is_not_closure

foobar.call #=> 1
foobar.call #=> 1
foobar.call #=> 1

クロージャになってません😅

クロージャになる例

クロージャになる例です。

def this_is_closure
  i = 0

  Proc.new do
    i += 1
  end
end

上記のように定義した this_is_closure をクロージャであると仮定して、実行してみます。

foobar = this_is_closure

foobar.call #=> 1
foobar.call #=> 2
foobar.call #=> 3

無事クロージャになりました😀

考察

クロージャの作り方としては上記のように書けばよいです。が、クロージャは、(少なくとも私は)とても技巧的な書き方だと思いますし*2、同様の機能を持たせるための書き方はたいてい他にもあり、そちらの書き方の方が可読性が高いと思っています。

となると疑問としては「なぜクロージャを使うのか」ということになります。

その点については記事にまとめてくださった方がいらっしゃり、分かりやすいので参考にしてみてください。変数のスコープの性質上、JavaScript で用いられることにやはり意義が高そうです。

artgear.hatenablog.com

参考

「プロを目指す人のためのRuby入門」を参考にしました。名著です。

gihyo.jp

*1:初見でこれを理解できる人を尊敬します

*2:よくこんな書き方思いついたな、と最初思いました

Powered by はてなブログ