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
次はもう少し実用的なサンプルを作る予定。