my.code();

my.code();

  • Python
    • 1.環境構築と基本思想
    • 2.基本構文とデータ型
    • 3.リスト、タプル、辞書、セット
    • 4.制御構文と関数
    • 5.モジュールとパッケージ
    • 6.オブジェクト指向プログラミング
    • 7.ファイルの入出力とコンテキストマネージャ
    • 8.例外処理
    • 9.ジェネレータとデコレータ
  • Ruby
    • 1.rubyの世界へようこそ
    • 2.基本構文とデータ型
    • 3.制御構造とメソッド定義
    • 4.すべてがオブジェクト
    • 5.コレクション (Array, Hash, Range)
    • 6.ブロックとイテレータ
    • 7.クラスとオブジェクト
    • 8.モジュールとMix-in
    • 9.Proc, Lambda, クロージャ
    • 10.標準ライブラリの活用
    • 11.テスト文化入門
    • 12.メタプログラミング入門
  • C++
    • 1.C++の世界へようこそ
    • 2.型システムとメモリ
    • 3.関数と参照
    • 4.ポインタと動的メモリ
    • 5.クラスの基礎
    • 6.クラスを使いこなす
    • 7.継承とポリモーフィズム
    • 8.テンプレート
    • 9.STL ①:コンテナ
    • 10.STL ②:アルゴリズムとラムダ式
    • 11.RAIIとスマートポインタ
    • 12.プロジェクトの分割とビルド

第6章: ブロックとイテレータ - Rubyの最重要機能

Rubyの学習において、ブロック (Block) は最も重要で強力な機能の一つです。他言語の経験者にとって、これはラムダ式や無名関数、クロージャに似た概念ですが、Rubyではこれが言語構文の核に深く組み込まれています。

この章では、ブロックの使い方と、ブロックを活用する「イテレータ」と呼ばれるメソッドを学びます。

ブロック構文: do...end と {}

ブロックとは、メソッド呼び出しに渡すことができるコードの塊です。メソッド側は、受け取ったそのコードの塊を好きなタイミングで実行できます。

ブロックには2種類の書き方があります。

  1. { ... } (波括弧): 通常、1行で完結する場合に使われます。
  2. do ... end: 複数行にわたる処理を書く場合に使われます。

どちらも機能的にはほぼ同じです。最も簡単な例は、指定した回数だけブロックを実行する times メソッドです。

3.times というメソッド呼び出しの後ろに { ... } や do ... end で囲まれたコードブロックを渡しています。times メソッドは、そのブロックを3回実行します。

代表的なイテレータ

Rubyでは、コレクション(配列やハッシュなど)の各要素に対して処理を行うメソッドをイテレータ (Iterator) と呼びます。イテレータは通常、ブロックを受け取って動作します。

代表的なイテレータを見ていきましょう。

each

each は、コレクションの各要素を順番に取り出してブロックを実行します。他言語の foreach ループに最も近いものです。

|n| の部分はブロック引数と呼ばれ、イテレータが取り出した要素(この場合は配列の各要素)を受け取ります。

Note: each メソッドの戻り値は、元の配列 ([1, 2, 3]) 自身です。each はあくまで「繰り返すこと」が目的であり、ブロックの実行結果は利用しません。

map (collect)

map は、各要素に対してブロックを実行し、そのブロックの戻り値を集めた新しい配列を返します。

map は、元の配列を変換した新しい配列が欲しい場合に非常に便利です。

select (filter)

select は、各要素に対してブロックを実行し、ブロックの戻り値が真 (true) になった要素だけを集めた新しい配列を返します。

find (detect)

find は、ブロックの戻り値が真 (true) になった最初の要素を返します。見つからなければ nil を返します。

Enumerableモジュール:イテレーションの力

each, map, select, find といった便利なメソッドは、実は Enumerable(エニューメラブル)というモジュールによって提供されています。

Enumerable はRubyの「Mix-in(ミックスイン)」機能の代表例です。これは、クラスに「混ぜ込む」ことで、そのクラスのインスタンスに特定の機能(メソッド群)を追加する仕組みです。

Enumerable をMix-inするクラス(例えば Array や Hash, Range)が満たすべき契約はただ一つ、each メソッドを実装することです。

each メソッドさえ定義されていれば、Enumerable モジュールは each を使って map, select, find, sort, count など、数十もの便利なイテレーションメソッドを自動的に提供してくれます。

例えば、Array クラスは each を持っています。

これは、自分で新しいコレクションクラスを作った場合でも同様です。(include については後の「モジュールとMix-in」の章で詳しく学びます)

my_collection.rb
ruby my_collection.rb

このように、Rubyのイテレータの強力さは Enumerable モジュールによって支えられています。Rubyでは、**「each メソッドを持つものは、すべて Enumerable である(あるいはそう振る舞える)」**という考え方が非常に重要です。

for ループとの比較

他言語経験者の方は、for ループを使いたくなるかもしれません。

// C や Java の for ループ for (int i = 0; i < 3; i++) { printf("Hello\n"); }

Rubyにも for 構文は存在します。

しかし、Rubyの世界では for ループはほとんど使われません。なぜなら、for は内部的に each メソッドを呼び出しているに過ぎないからです。

Rubyプログラマは、for よりも each などのイテレータをブロックと共に使うことを圧倒的に好みます。イテレータの方が、何をしているか(単なる繰り返し、変換、選択など)がメソッド名 (each, map, select) から明確であり、コードが読みやすくなるためです。

ブロック引数とブロックの戻り値

すでに出てきたように、ブロックは | ... | を使って引数を受け取ることができます。

また、ブロックも(Rubyのすべての式と同様に)戻り値を持ちます。ブロックの戻り値とは、ブロック内で最後に評価された式の値です。

  • each はブロックの戻り値を無視します。
  • map はブロックの戻り値を集めて新しい配列にします。
  • select はブロックの戻り値が真か偽かを判定に使います。

yield:ブロックを受け取るメソッド

では、どうすればブロックを受け取るメソッドを自分で作れるのでしょうか? それには yield というキーワードを使います。

メソッド内で yield が呼び出されると、そのメソッドに渡されたブロックが実行されます。

yield_basic.rb
ruby yield_basic.rb

yield はブロックに引数を渡すこともできます。

yield_with_args.rb
ruby yield_with_args.rb

each や map のようなイテレータは、内部でこの yield を使って、コレクションの各要素をブロックに渡しながら実行しているのです。

この章のまとめ

  • ブロックは、メソッドに渡せるコードの塊で、{}(1行)または do...end(複数行)で記述します。
    • イテレータは、ブロックを受け取り、要素の繰り返し処理を行うメソッドです(each, map, select など)。
    • Enumerableモジュールは、 each を実装するクラスに map や select などの強力なイテレーション機能を提供します。
    • Rubyでは for ループよりもイテレータが好まれます。
    • ブロックは |arg| で引数を受け取ることができ、ブロックの最後の式の値が戻り値となります。
    • 自作メソッド内で yield を使うと、渡されたブロックを実行できます。

練習問題1

数値の配列 [1, 2, 3, 4, 5] があります。map イテレータとブロックを使って、各要素を文字列に変換し(例: 1 → "1")、 "1", "2", "3", "4", "5" という文字列の配列を作成してください。

practice6_1.rb
ruby practice6_1.rb

練習問題2

文字列の配列 ["apple", "banana", "cherry", "date"] があります。select イテレータとブロックを使って、文字数が5文字以上の果物だけを抽出した新しい配列(["apple", "banana", "cherry"])を作成してください。

practice6_2.rb
ruby practice6_2.rb