(ruby)(Rubyのイテレーターの基礎をまとめてみた)
eachなどでよく利用されている便利なイテレーターですが
いざ自分でそういったものを定義してみようとなると
「ワケガワカラン・・・」と挫折しそうになってしまうので
出来る限り噛み砕いて理解してみることにしました
これは、それをまとめた物ですので 内容に誤りがあるかもしれません
また、見やすくするため、理解しやすくするため
というかそもそも私のクセのため
省略可能な括弧もあえて書いています
あらかじめご了承ください
まずイテレーターを実現するための 基礎となる形は
つまり メソッド定義の yield()の部分が
呼び出し側のブロックの部分と「置き換えられて」実行されます
(ただし これは反復処理をしてないので まだイテレーターとは呼べません)
「置き換えられて」ということなので
ブロックの最終行の結果が yield()の戻り値になります
つまり「ブロック内の結果を元に処理をすることも可能」という事になります
これが出来ると何が出来るのかというと
ブロック側で値の編集などが出来るようになります
このようにすれば二つ三つと値を渡す事が出来ます
あくまでも メソッド定義の一つなんですから
呼び出し側から 引数で値を渡す事も出来ます
(そして、配列の要素分反復するので、ここで初めてイテレーターと呼べる形になります)
今度は 既に有るクラスに機能追加する方法を考えてみます
配列の各要素がブロック内の条件を満たしているかどうかを調べて列挙し
真偽の数もカウントして表示します
いざ自分でそういったものを定義してみようとなると
「ワケガワカラン・・・」と挫折しそうになってしまうので
出来る限り噛み砕いて理解してみることにしました
これは、それをまとめた物ですので 内容に誤りがあるかもしれません
また、見やすくするため、理解しやすくするため
というかそもそも私のクセのため
省略可能な括弧もあえて書いています
あらかじめご了承ください
まずイテレーターを実現するための 基礎となる形は
def sample001() yield() end sample001(){ puts('hello') }
helloになります
つまり メソッド定義の yield()の部分が
呼び出し側のブロックの部分と「置き換えられて」実行されます
(ただし これは反復処理をしてないので まだイテレーターとは呼べません)
「置き換えられて」ということなので
ブロックの最終行の結果が yield()の戻り値になります
つまり「ブロック内の結果を元に処理をすることも可能」という事になります
def sample002() if yield() then puts('true') return('true') else puts('false') return('false') end end puts('>>' << sample002(){100.even?}) puts('>>' << sample002(){111.even?})
true >>true false >>false続いて、ブロックの方へ値を値を渡す方法です
これが出来ると何が出来るのかというと
ブロック側で値の編集などが出来るようになります
def sample003() puts(yield('hello')) end sample003(){|x| '>>>' << x << '<<<' }
>>>hello<<<ブロック側に複数個の値を渡したい場合は
このようにすれば二つ三つと値を渡す事が出来ます
def sample004() puts(yield('hello','world')) end sample004(){|x,y| '>>>' << x << '<<< >>>' << y << '<<<' }
>>>hello<<< >>>world<<<これらは特殊な動きをするとはいえ
あくまでも メソッド定義の一つなんですから
呼び出し側から 引数で値を渡す事も出来ます
(そして、配列の要素分反復するので、ここで初めてイテレーターと呼べる形になります)
def sample005(val) val.each{|dat| if yield(dat) then puts('' << dat.to_s << ' is even') else puts('' << dat.to_s << ' is odd') end } end sample005([5,10,7,3,1,2,8,15,16]){|x| x.even? }
5 is odd 10 is even 7 is odd 3 is odd 1 is odd 2 is even 8 is even 15 is odd 16 is evenここまでは 普通にメソッド定義をしただけでしたが
今度は 既に有るクラスに機能追加する方法を考えてみます
class Array def enum_check(str = '') c1 = 0 c2 = 0 puts('> ' << str << ' <') self.each{|dat| if yield(dat) then c1 += 1 puts('' << dat.to_s << ' is true') else c2 += 1 puts('' << dat.to_s << ' is false') end } puts('true=' << c1.to_s() << ' false=' << c2.to_s()) end end [5,10,7,3,1,2,8,15,16].enum_check('greater than 5'){|x| x>5}
> greater than 5 < 5 is false 10 is true 7 is true 3 is false 1 is false 2 is false 8 is true 15 is true 16 is true true=5 false=4このサンプルの場合だと
配列の各要素がブロック内の条件を満たしているかどうかを調べて列挙し
真偽の数もカウントして表示します