Vol.7 ~ブロック~
○ ブロック
コードブロックやイテレータブロックと呼ばれ、まとめて実行したいコードを集めたもの。
○ イテレータ
コレクション.イテレータメソッド{|変数| 処理内容}
要素を順に返すイテレータメソッド「each」
>> [1, 2, 3].each{|i| puts i * 10} # 各要素10を掛けて出力する
10
20
30
=> [1, 2, 3]
イテレータメソッドを呼び出すと、コレクションの要素がブロック内の「変数」に渡され、「処理内容」を実行する。
ハッシュの場合は、変数の部分が「キー」と「バリュー」の2つになる。
>> {:uno => 1, :dos => 2} .each do |key, val|
>> puts key
>> puts val
>> end
uno
1
dos
2
=> {:uno => 1, :dos => 2}
イテレータに限らず、後ろにブロックをつけてメソッドを呼び出すこの形を「ブロックつきメソッド呼び出し」という。
○ ブロックつきメソッドの実装
>> def threetimes
>> if block_given? # ブロックが渡されたときに true となる
>> yield "1!" # ブロックを実行するためのキーワード
>> yield "2!"
>> yield "3!"
>> end
>> end
=> nil
>> threetimes{|n| puts n} # yield の後ろの文字列が n に渡される
1!
2!
3!
=> nil
○ Procオブジェクト
Ruby ではブロックをメソッドの後ろに配置することしかできない。
しかし、「Proc オブジェクト」を作成して「名づけ」をすると、あとからメソッドに渡すことが可能。
Proc オブジェクトを使用するには、以下の2つの手順が必要。
1) Procオブジェクトの作成
「Proc.new」の引数としてブロックを渡すことでProcオブジェクトを作成。
>> proc = Proc.new{|n| puts n}
または、
>> proc = lambda{|n| puts n}
2) Procオブジェクトを使ったメソッドの呼び出し。
作成したProcオブジェクトを、頭に「&」をつけてインテレータメソッドに渡す
>> [1, 2, 3].each &proc
1
2
3
=> [1, 2, 3]
○ クロージャとブロック
ブロックをある環境に結びつけることを「クロージャ」と呼ぶ。
>> # e の給料は amount よりも高いかどうか
>> def paidMore(amount)
>> retunr Proc.new{|e| e.salary > amount}
>> end
>> #paidMore を呼び出す際に、引数 150 を設定して、戻り値である Proc オブジェクトを変数に代入
>> highPaid = paidMore(150)
これで、環境と結びついたブロック(クロージャ)の完成。
このクロージャは「e の給料は 150 よりも高いかどうか」という処理を行う。
クロージャの実際の使い方
>> # クラス Employee を、インスタンス変数 salary と定義
>> class Empoloyee
>> attr_accessor :salary
>> end
=> nil
>> jon = Employee.new # インスタンス生成
=> #<Employee:0x2e66fd4>
>> john.salary = 200 # 値の設定
=> 200
>> highPaid.call(john) # クロージャ「highPaid」 をメソッド「call」で呼び出す
=> true # john の給料 200 は 150 より高いので ture
○ そのほかのブロックの使い方
ファイルIO などにも使用できる。
例えば、「File.open」にブロックを渡すと、ブロック終了時にファイルストリームのクローズを行ってくれるため、自分で管理する必要がない。
>> File.open("hello.rb") do |file|
>> puts file.read # ファイルの中身を読み込む
>> end