クラス内にイテレータ定義

スポンサーリンク
スポンサーリンク
ライフスタイル関連のコンテンツ
お金 | 仕事 | 勉強 | プライベート | 健康 |
プログラミング関連のコンテンツ
C言語/C++入門 | Ruby入門 | Python入門 | プログラミング全般

イテレータを定義する・まずは未定義のクラスの例で、イテレータ未定義のクラスの例を見ました。

スポンサーリンク

注目するのは、「pp proflist」で確認できるProfListのオブジェクトの中身です。
以下のようになっています。

#<ProfList:0x29a2ca0
 @proflist=
  [#<Prof:0x29a2b4c @age=45, @country="America", @name="Tom William">,
   #<Prof:0x29a2b10 @age=23, @country="Spain", @name="De Pedoro">,
   #<Prof:0x29a2ad4 @age=37, @country="Japan", @name="Naoko Yamada">]>

オブジェクトのメモリアドレスと、インスタンス変数「@proflist」が配列となっています。
ProfListクラスの中で、以下のように初期化しているので、@proflistが配列であることは当然です。

def initialize()
    @proflist = Array.new
end

クラス内にイテレータを定義する場合には、この配列であるインスタンス変数「@proflist」をレシーバとする、eachメソッドを以下のように定義します。

def each
    @proflist.each{|prof|
        yield(prof)    
    }
end

yield文がキモとなる部分です。
メソッド定義の中のyield文は、定義しているメソッドに与えられたブロックを実行します。

proflist.each{|prof|
    puts "#{prof.name} - age:#{prof.age} country:#{prof.country}"
}

と、新しく独自定義したイテレータ(eachメソッド)を呼び出すと・・・

{|prof|
    puts "#{prof.name} - age:#{prof.age} country:#{prof.country}"
}

のブロック部分を、yieldが受け取り実行するようなイメージです。
これで、クラス内に新しいイテレータを定義できました。
以下、改良したクラスとテストルーチンです。

require "pp"
 
# 1人のプロフィールのクラス。名前、年齢、出身国
class Prof
    attr_accessor :name, :age, :country
    def initialize(name, age, country=nil)
        @name = name
        @age = age
        @country = country
    end
end
 
# プロフィールのリストのクラス
class ProfList
    def initialize()
        @proflist = Array.new
    end
    # 新しい人を加える
    def add(prof)
        @proflist.push(prof)
    end
    # 人数を返す
    def length
        @proflist.length
    end
    # n番目の人を別の人に入れ替える
    def []=(n, prof)
        @proflist[n] = prof
    end
    # n番目の人を返す
    def [](n)
        @proflist[n]
    end
    # リストからプロフィールを削除
    def delete(prof)
        @proflist.delete(prof)
    end
    # イテレータ定義
    def each
        @proflist.each{|prof|
            yield(prof)    
        }
    end
end
 
# テストルーチン
proflist = ProfList.new
 
# プロフィールをいくつか作る
p1 = Prof.new("Tom William", 45, "America")
p2 = Prof.new("De Pedoro", 23, "Spain")
p3 = Prof.new("Naoko Yamada", 37, "Japan")
 
# プロフィールリストに人(プロフィール)を追加
proflist.add(p1)
proflist.add(p2)
proflist.add(p3)
 
# プロフィールを1人ずつ表示
proflist.length.times{|i|
    puts "#{proflist[i].name} - age:#{proflist[i].age} country:#{proflist[i].country}"
}
 
# プロフィールを1人ずつ表示。
# 今度はProfListクラスに、新しいイテレータとしてeachメソッドを定義したのでOK。
puts "--- original iterator"
proflist.each{|prof|
    puts "#{prof.name} - age:#{prof.age} country:#{prof.country}"
}
 

実行結果。

Tom William - age:45 country:America
De Pedoro - age:23 country:Spain
Naoko Yamada - age:37 country:Japan
--- original iterator
Tom William - age:45 country:America
De Pedoro - age:23 country:Spain
Naoko Yamada - age:37 country:Japan
スポンサーリンク
 
スポンサーリンク