読み込み中...

Rubyパターンマッチング完全解説!10手法を詳細サンプルコードで学ぶ

Rubyパターンマッチングのサンプルコードと詳細解説のイメージ画像 Ruby
この記事は約11分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

あなたがRubyでプログラミングをしているなら、パターンマッチングの存在は知っておくべき重要な要素です。

パターンマッチングは、その名の通り、特定の「パターン」にデータが「マッチ」するかどうかを判定し、データの構造を確認したり、その中から必要な情報を取り出したりする技術です。

●Rubyとパターンマッチングの基本

Rubyは、パターンマッチングをサポートしている数少ない言語の一つであり、それはこの言語の柔軟性と多様性をより一層強化しています。

Rubyのパターンマッチングは、あらゆるデータ型やオブジェクトに対して有効で、その用途は極めて広範にわたります。

●パターンマッチングの使い方

○パターンマッチングの基本形

Rubyのパターンマッチングの最も基本的な形は、リテラルとの比較です。

次のコードを見てください。

case value
in 1
  puts 'value is 1'
in 2
  puts 'value is 2'
else
  puts 'value is not 1 or 2'
end

このコードでは、caseinを使ってvalueの値が1か2かそれ以外かを判断しています。

この例では、valueが1ならば”value is 1″を出力し、2ならば”value is 2″を出力し、それ以外ならば”value is not 1 or 2″を出力します。

○パターンマッチングの応用形

パターンマッチングは単純な値だけでなく、配列やハッシュ、オブジェクトなどにも適用できます。

その応用形の一つを次のコードで紹介します。

case person
in { name: "John", age: age }
  puts "John is #{age} years old."
else
  puts "Not John."
end

このコードでは、personというハッシュがあると仮定し、その中にnameが”John”で、ageが何かの値を持つ場合をマッチングしています。

“John”であればその年齢を出力し、それ以外なら”Not John.”を出力します。

●10のパターンマッチング手法とサンプルコード

Rubyのパターンマッチングはその名の通り、与えられたデータが特定のパターンにマッチするかを確認し、それに基づいて処理を行います。

パターンマッチングの10の手法を詳細なサンプルコードとともに紹介します。

○手法1:単純な値のマッチング

まずは単純な値のマッチングから始めましょう。

このコードはvalueの値が1, 2, またはそれ以外かを判断します。

value = 1
case value
in 1
  puts 'value is 1'
in 2
  puts 'value is 2'
else
  puts 'value is not 1 or 2'
end

上記のコードを実行すると、’value is 1’と出力されます。

これは、valueの値が1であるため、最初のパターンにマッチするからです。

○手法2:配列のマッチング

次に、配列のマッチングについて見てみましょう。

このコードでは、配列の要素がマッチするかどうかをチェックします。

array = [1, 2]
case array
in [1, 2]
  puts 'Matched!'
else
  puts 'Not Matched!'
end

このコードは、’Matched!’を出力します。

なぜなら、arrayの要素がパターン[1, 2]と完全に一致するからです。

○手法3:ハッシュのマッチング

ハッシュのマッチングは、キーと値のペアがマッチするかどうかをチェックします。

person = { name: "John", age: 30 }
case person
in { name: "John", age: age }
  puts "John is #{age} years old."
else
  puts "Not John."
end

このコードは”John is 30 years old.”と出力します。

この場合、ハッシュのキーと値がパターンと一致しているため、マッチングは成功します。

○手法4:クラスのマッチング

Rubyのパターンマッチングでは、オブジェクトのクラスによってマッチングを行うことも可能です。

下記のコードは、与えられた値が整数かどうかをチェックする一例です。

value = 1
case value
in Integer
  puts "value is an Integer."
else
  puts "value is not an Integer."
end

上記のコードを実行すると、”value is an Integer.”と出力されます。

valueの値が整数(Integer)であるため、このパターンにマッチします。

○手法5:条件付きマッチング

パターンマッチングでは条件を指定してマッチングを行うこともできます。

下記のコードでは、与えられた数値が正の整数であることを確認します。

value = 5
case value
in Integer if value > 0
  puts "value is a positive integer."
else
  puts "value is not a positive integer."
end

このコードを実行すると、”value is a positive integer.”と表示されます。

valueが正の整数であるため、この条件付きパターンにマッチします。

○手法6:無名関数のマッチング

Rubyのパターンマッチングは、無名関数(ラムダ)と組み合わせることも可能です。

下記のコードは、数値が偶数かどうかをラムダを使ってチェックします。

value = 2
even = ->(n) { n % 2 == 0 }
case value
in even
  puts "value is even."
else
  puts "value is not even."
end

上記のコードを実行すると、”value is even.”と出力されます。

無名関数evenは引数nが偶数であるかどうかを確認します。

valueが偶数であるため、このパターンにマッチします。

このように、Rubyのパターンマッチングは非常に柔軟性が高く、さまざまなパターンに対応することができます。

○手法7:複数のパターンマッチング

Rubyのパターンマッチングでは、複数のパターンを一度に処理することも可能です。

下記のコードは、与えられた値が整数、浮動小数点数、または文字列かどうかをチェックする例です。

value = 1.5
case value
in Integer
  puts "value is an Integer."
in Float
  puts "value is a Float."
in String
  puts "value is a String."
else
  puts "value is not an Integer, Float, or String."
end

このコードを実行すると、「value is a Float.」と表示されます。

値が浮動小数点数(Float)であるため、このパターンに一致します。

パターンマッチングの強力なところは、さまざまな条件を簡潔に表現できることです。

○手法8:結果の取り出し

パターンマッチングでは、マッチした結果を取り出してさらに処理を行うことができます。

下記のコードでは、配列の中から特定の要素を取り出す例を示します。

array = [1, 2, 3]
case array
in [first, *rest]
  puts "The first element is #{first}."
  puts "The rest of the elements are #{rest}."
end

このコードを実行すると、「The first element is 1.」「The rest of the elements are [2, 3].」と表示されます。

パターンマッチングを使用することで、特定の条件に一致する要素を効率的に取り出すことができます。

○手法9:例外処理とパターンマッチング

Rubyのパターンマッチングは例外処理と組み合わせることも可能です。

下記のコードは、発生した例外の種類によって異なる処理を行う例を示します。

begin
  # risky operation
rescue => e
  case e
  in StandardError
    puts "Caught a standard error."
  in RuntimeError
    puts "Caught a runtime error."
  else
    puts "Caught an unexpected error."
  end
end

上記のコードでは、発生した例外がどのクラスに属するかによって異なるメッセージを出力します。

例外処理とパターンマッチングを組み合わせることで、より具体的で適切なエラーハンドリングを実現することができます。

○手法10:データの変形とパターンマッチング

Rubyのパターンマッチングでは、データの変形を行いながらパターンマッチングを適用することもできます。

例えば、ある配列の中に、特定の形状のデータが含まれているかどうかを調べることができます。

下記のコードでは、配列内のハッシュが特定のキーを持っているかどうかをチェックしています。

data = [{name: 'Alice', age: 20}, {name: 'Bob', age: 30}, {name: 'Charlie', age: 40}]
case data
in [{name: a_name}, *]
  puts "The name of the first person is #{a_name}."
else
  puts "The array does not contain the expected structure."
end

このコードを実行すると、「The name of the first person is Alice.」と出力されます。

このようにパターンマッチングを利用することで、特定の形状を持つデータを効率的に検出し、その情報を取り出すことが可能になります。

●注意点と対処法

パターンマッチングは強力なツールでありながら、いくつかの注意点があります。

一つは、マッチングの順序です。

Rubyのパターンマッチングは上から順にマッチングを試みるため、より具体的なパターンを上位に配置することが重要です。

例えば、具体的な値と変数のパターンがある場合、具体的な値を先にチェックしなければ、変数が先にマッチしてしまい、期待した結果が得られないことがあります。

二つ目は、パターンマッチングの対象となるデータの形状です。

配列やハッシュなど、形状が異なるデータに対して同じパターンを適用すると、意図しない結果が得られることがあります。

そのため、パターンマッチングを適用する前に、データの形状を確認することが大切です。

●パターンマッチングのカスタマイズ方法

Rubyのパターンマッチングはカスタマイズが可能です。

例えば、自分で定義したクラスに対してパターンマッチングを適用したい場合、deconstructメソッドをクラスに定義することで、そのクラスのインスタンスに対するパターンマッチングが可能になります。

class Person
  attr_reader

 :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def deconstruct
    [@name, @age]
  end
end

alice = Person.new('Alice', 20)
case alice
in Person[name, age]
  puts "#{name} is #{age} years old."
end

このコードでは、Personクラスのインスタンスが持つ@name@ageを配列として返すdeconstructメソッドを定義しています。

これにより、Personクラスのインスタンスに対してパターンマッチングを行い、その結果を取り出すことができます。

このコードを実行すると、「Alice is 20 years old.」と表示されます。

これにより、Rubyのパターンマッチングを、標準のデータ型だけでなく、自分で定義したクラスに対しても適用することができます。

まとめ

Rubyのパターンマッチングは、コードの可読性と効率性を向上させる強力なツールです。

様々なデータ構造に対して適用可能であり、複雑な条件分岐やデータの抽出を簡潔に表現することができます。

ただし、マッチングの順序やデータの形状に注意を払いながら、適切に利用することが重要です。

また、自分で定義したクラスに対してもパターンマッチングを適用することが可能で、さらなる柔軟性を持たせることができます。

これらのテクニックを理解し活用することで、Rubyプログラミングの可能性が広がります。