******************** ブロック付きメソッド ******************** * `ブロック付きメソッド呼び出し `_ * `これで完璧!Rubyのブロックの使い方、使い道まとめ(貝原 輝昌) `_ もともとは、配列などのデータ構造の各要素に対して、繰り返し同じ処理をするために考えられた。そのため、以前はイテレータと呼ばれていた。 ========== ブロック ========== ``do`` ... ``end`` または ``{`` ... ``}`` の形をしたもの。 .. code-block:: ruby x.each do puts 'Hello world' end x.each { puts 'Hello world' } ``do`` ... ``end`` と ``{`` ... ``}`` は意味は同じだが、構文的な結合の強さが違うので注意。 .. code-block:: ruby foo bar do puts 'Hello world' end # foo(bar) do puts 'Hello world' end と同じ foo bar { puts 'Hello world' } # foo( bar { puts 'Hello world' } ) と同じ .. code-block:: ruby [1, 2, 3].inject 0 do |s, i| s += i end # => 6 [1, 2, 3].inject 0 { |s, i| s += i } # エラー .. note:: ``while`` や ``for`` の後の ``do`` ... ``end`` はブロックではない(スコープを作らない)ので注意。スコープについては :ref:`scope` を参照。 ================ ブロックの引数 ================ ブロックの先頭に縦棒で囲んで変数名を書くと、ブロックの引数になる。メソッド(関数)定義の引数とだいたい同じ。 引数に何が渡されるかはメソッドによって違う。 .. code-block:: ruby x = [ 1, 2, 3 ] sum = 0 x.each do |i| # i に配列の各要素が代入される sum += i end .. code-block:: ruby x = [ 1, 2, 3 ] x.inject(0) do |sum, i| # 前の繰り返しの結果が sum に、次の要素が i に代入される sum + i end .. code-block:: ruby IO.foreach('words.txt') do |line| # line にファイルの各行が代入される puts line end .. code-block:: ruby open('random.txt', 'w') do |f| # f にファイルハンドラが代入される f.puts rand(100) end # ブロックの終了で自動的にクローズ .. admonition:: 課題6 :class: exercise `Gutenbergプロジェクトの単語リスト `_ をダウンロードして ``CROSSWD.TXT`` というファイルに保存せよ。この中で最も長い単語を探して出力するプログラムを書け。ただし、文字列 ``line`` の長さは ``line.length`` でわかる。同じ長さの単語が複数ある場合は、どれか一個だけ出力すればよい。 :ref:`【解答例】 ` .. _scope: ====================== ローカル変数のスコープ ====================== * `ローカル変数 `_ * `Rubyの変数5種類の解説とサンプル、有効範囲(スコープ)について(Gabekore Garage) `_ * `Ruby 変数とスコープ スクリプトの書き方(バイオインフォ道場) `_ Rubyでは明示的な変数宣言はなく、最初に代入した時に宣言したことになる。 ローカル変数のスコープは、宣言(最初の代入)を含む最も内側のブロックやメソッド定義の中だけ。 .. code-block:: ruby def foo x = 1 # x は foo の中で宣言 [1, 2, 3].each do |i| # i はブロックの中で宣言 puts x # x はfooの中で有効なので大丈夫 end puts i # i はブロックの中で有効なので外で使うとエラーになる end .. note:: ブロックは外側のローカル変数も使えるが、メソッド定義は外側のローカル変数は使えない。 .. code-block:: ruby def foo x = 1 # x は foo の中で宣言される def bar puts x # foo と bar は違うスコープなのでエラーになる end bar end ============================== ブロック付きメソッドの作り方 ============================== * `yield `_ * `【初心者必見】Ruby yieldについて知る!(侍エンジニア塾ブログ) `_ ブロック付きメソッドの定義の仕方は普通のメソッドと同じ。メソッド本体の中で ``yield`` を実行すると、そこで指定した値をブロックのパラメータに渡して、ブロック内部を実行する。 .. code-block:: ruby def foo yield 1 yield 2 yield 3 end foo do |x| puts x end .. code-block:: ruby def foo(x, y) yield x, y end foo(1, 2) do |i, j| puts i+j end ブロック付きメソッドは、コールバック関数を簡単に書けるようにしたものと言える。他の言語だと関数を明示的に渡すことが多い。上の例を、関数を明示的に渡すように書きなおすと次のようになる。 .. code-block:: ruby def foo(func) func.call 1 func.call 2 func.call 3 end foo( lambda{ |x| puts x } ) .. code-block:: ruby def foo(x, y, func) func.call x, y end foo(1, 2, lambda{ |i, j| puts i+j }) .. admonition:: 課題7 :class: exercise 2個の配列とブロックを受け取り、配列の各要素ごとにブロックで指定された演算を行うメソッド ``arraycalc`` を作れ。 例えば、 ``arraycalc([1,2,3], [4,5,6]){|x,y| x*y}`` は、まず ``x=1`` と ``y=4`` に対して ``x*y`` を計算して4、他の要素は同様に10, 18となるので、配列 ``[4,10,18]`` を返す。 ただし、引数が配列でない場合や、配列の要素の個数が一致しない場合は考えなくてよい。 :ref:`【解答例】 `