LoginSignup
14

More than 5 years have passed since last update.

Rubyでクロージャを使いたい(導入編)

Last updated at Posted at 2015-11-02

Procクラスとかラムダ式とかクロージャとかって知識としては知ってるけど、実際に使うことってあんまりない。というか使う腕がない、でも使いこなしたい。というわけで今回は初歩的なサンプルをいくつか作ってみる。ちなみにクロージャやProcクラスそのものについての説明はありません。以下のリンクが参考になるかも。

クロージャ-Wikipedia
[Ruby] ブロックやProcの使いどころを理解する

サンプル1: カウンター

指定回数実行するとfalseを返し、回数に届くまではtrueを返すインスタンスを作成したい。例えば以下のような感じ。

count_5は4回目まではcallするたびにtrueを返すが、5回目からはfalseを返す。

count_5.call #true
count_5.call #true
count_5.call #true
count_5.call #true
count_5.call #false
count_5.call #false

これを実現するには、まずは次のようなcounterメソッドを定義する

def counter(n)
    count = n
    ->{
        count -= 1
        count > 0
    }
end

そしてcounterメソッドを参照する変数を宣言する。

count_5 = counter 5

falseを返すようになるタイミングはcounterメソッドの引数で指定できるようにしてある。以下のサンプルでは3回と5回のカウンターを作成して使用している。

#counterメソッドの宣言
def counter(n)
    count = n
    ->{
        count -= 1
        count > 0
    }
end

count_3 = counter 3 
count_5 = counter 5

p count_3.call
p count_3.call
p count_3.call
p count_3.call

while count_5.call do
    p "hello"
end

結果

true
true
false
false
"hello"
"hello"
"hello"
"hello"

実用性は特にないけどサンプルとしては分かりやすいと思う。

サンプル2:素数を順番に数える

callするたびに特定の整数nよりも大きい素数を順番に返すインスタンスを作成したい。例えば次のような感じ

prime_number_over_10はcallするたびに10より大きい素数を順番に返す。

prime_count_over_10.call #11
prime_count_over_10.call #13
prime_count_over_10.call #17
prime_count_over_10.call #19

まずは以下のようなprime_countメソッドを定義する。ちなみにPrime#primer?メソッドは引数が素数ならtrueを返す。

require 'prime'

def prime_count(n)
    count ||= n
    ->{
        count += 1
        while !Prime.prime?(count)
            count += 1
        end
        return count
    }
end

そしてprime_countメソッドを参照する変数を宣言する。

prime_count_over_10 = prime_count 10

prime_count_over_10はprime_countメソッドの引数で指定した整数(今回は10)よりも大きい素数を順番に返す。以下のサンプルでは10より大きい素数と1000より大きい素数をそれぞれ順番に5個ずつ出力している。

require 'prime'

def prime_count(n)
    count ||= n
    ->{
        count += 1
        while !Prime.prime?(count)
            count += 1
        end
        return count
    }
end

prime_count_over_10 = prime_count 10
prime_count_over_1000 = prime_count 1000

5.times do p prime_count_over_10.call end

print "\n"

5.times do p prime_count_over_1000.call end

結果

11
13
17
19
23

1009
1013
1019
1021
1031

このサンプルで行ったようなことは、Prime#モジュールのメソッドを使用すれば簡単に実装できるんだけど、今回はあくまでも練習なのでPrime#モジュールの使用は最低限に控えてあります。

サンプル3: ON・OFFスイッチ

callするたびにtrueとfalseを交互に返すインスタンスを作成したい。具体的には以下のような感じ

on_off_switchは奇数回目のcallではtrueを返すが、偶数回目のcallではfalseを返す。

on_off_switch.call #true
on_off_switch.call #false
on_off_switch.call #true
on_off_switch.call #false

これを実現するために、まずは以下のようなメソッドを作成する。

def onoff
    n = false
    ->{
        n = !n
    }
end

そして上記のonoffメソッドを参照する変数を宣言する。

on_off_switch = onoff

以下の例では、on_off_switchとサンプル2のprime_countを使用して、100以上の素数を小さい順から一つ飛ばしで10個出力している

require 'prime'

def prime_count(n)
    count ||= n
    ->{
        count += 1
        while !Prime.prime?(count)
            count += 1
        end
        return count
    }
end

def onoff
    n = false
    ->{n = !n}
end

prime_count_over_100 = prime_count 100
on_off_switch = onoff

20.times do
    prime_number = prime_count_over_100.call
    p prime_number if on_off_switch.call
end

結果


101
107
113
131
139
151
163
173
181
193

次はもう少し実用的なサンプルを作る予定。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14