メドピア開発者ブログ

集合知により医療を再発明しようと邁進しているヘルステックカンパニーのエンジニアブログです。読者に有用な情報発信ができるよう心がけたいので応援のほどよろしくお願いします。

Ruby3.0でのパターンマッチ機能の変更点

こんにちは、メドピアのサーバサイドエンジニアの草分です。

2020年12月25日、ついに待望のRuby3.0がリリースされましたね。

以前、Ruby2.7で発表されたパターンマッチについての記事を執筆したのですが、Ruby3.0になりいくつか追加/変更が入っています。 この記事ではそれらの変更点を確認していきます。

「Rubyのパターンマッチとは何ぞや?」という方は是非前回の記事も合わせてご覧ください。 tech.medpeer.co.jp

Ruby3.0を使うには

rbenvなど、主要なサードパーティツールが既にRuby3.0に対応しています。
それらを使ってインストールするのが簡単でしょう。

# rbenv
rbenv install 3.0.0
# rvm
rvm install ruby-3.0.0

Windowsの方は RubyInstaller for Windows などをお使いください。

rubyを実行しRUBY_VERSIONが3以降になっていれば準備完了です。

irb(main):001:0> RUBY_VERSION
=> "3.0.0"

1行パターンマッチ(experimental)

# version 3.0
{a: 0, b: 1} => {a:}
p a # => 0
# version 2.7
{a: 0, b: 1} in {a:}
p a # => 0

Ruby2.7ではパターンマッチのinを用いて右代入のようなことができていましたが、Ruby3.0からは=>を用いるように再設計されました。

下記のように分割代入をさせることもできます。

attrs = { name: 'メドピア太郎', email: 'med@example.com' }

attrs => { name:, email: }
p name # => "メドピア太郎"
p email # => "med@example.com"

一方、in は true/false を返すようになりました。 条件判定として使えそうですね。

{ a: 0, b: 1 } in { a: } # => true
{ a: 0, b: 1 } in { c: } # => false

Find Pattern(experimental)

case ["a", 1, "b", "c", 2, "d", "e", "f", 3]
in [*pre, String => x, String => y, *post]
  p pre  #=> ["a", 1]
  p x    #=> "b"
  p y    #=> "c"
  p post #=> [2, "d", "e", "f", 3]
end

* を指定することで、複数要素から要素数に関わらずマッチする部分のみ抽出できるようになるパターンも追加されました。

下記のように、Hashに対して条件指定と属性の抽出を同時に行う。といったこともできるようになります。

case [{name: "sato", age: 18}, {name: "tanaka", age: 15}, {name: "suzuki", age: 17}]
in [*, {name: "tanaka", age: age}, *]
  p age # => 15
end

case/inが実験的(experimental)な機能ではなくなった

irb(main):001:0> RUBY_VERSION
=> "3.0.0"
irb(main):002:1* case 0
irb(main):003:1* in a
irb(main):004:1*   puts a #=> 0
irb(main):005:0> end
0
=> nil

パターンマッチを利用してもexperimentalであることの警告が発生しなくなりました。

ただし、3.0で追加された1行パターンマッチやFind Patternについてはexperimentalのままです。要注意。

irb(main):001:0> {b: 0, c: 1} => {b:}
(irb):1: warning: One-line pattern matching is experimental, and the behavior may change in future versions of Ruby!

 

irb(main):001:1* case ["a", 1, "b", "c", 2, "d", "e", "f", 3]
irb(main):002:1*   in [*pre, String => x, String => y, *post]
irb(main):003:1*   p x    #=> "b"
irb(main):004:0> end
(irb):2: warning: Find pattern is experimental, and the behavior may change in future versions of Ruby!
"b"

おわりに

Ruby3.0のリリースノートからパターンマッチに関する部分を抜粋して紹介いたしました。参考になれば幸いです。

パターンマッチ自体の概要については前回の記事にまとめております。 こちらも是非ご覧ください。


是非読者になってください


メドピアでは一緒に働く仲間を募集しています。 ご応募をお待ちしております!

■募集ポジションはこちら

https://medpeer.co.jp/recruit/entry/

■開発環境はこちら

https://medpeer.co.jp/recruit/workplace/development.html