Articles

How to Write a Case Expression in Ruby

Posted on

オブジェクトの値をチェックして、それに基づいて異なるアクションを実行する方法が必要だと想像してください。

その前に、case式がどのように動作するか、また、上記の目的を達成するためにどのように使用できるかを見てみましょう。

ケースの仕組み

casecasewhenの部分です。

when===case 句は、それに渡される引数を定義します。

例を見てみましょう。

case awhen String #..end

ですから、上の例はString === aString.===(a)と考えることができます。

最後に、マッチしない場合に使えるelseという句もあります。

case my_objectwhen String "This is a string"else "I have no idea what this is"end

三重の等号演算子 (===)

デフォルトでは、case===) 演算子を使って比較を行います。

===の問題点は、等値性とは何の関係もないことです。 デフォルトでは、通常は 2 つのオブジェクトが同等の値を持つかどうかをチェックする double equals 演算子 (==) にエイリアスされていますが、何かを意味するように定義することもできます。

例えば、レンジでは includes?matchis_a? の別名として、procでは call の別名として定義できます。

この演算子はリテラルでは期待どおりに動作しますが、クラスでは動作しません。

1 === 1 # => trueNumeric === Numeric # => false

それは、===kind_of?kind_of?のドキュメントです。

kind_of?(class) → true or false

classがobjのクラスであるか、classがobjのスーパークラスの一つかobjに含まれるモジュールであればtrueを返します。

つまり、オブジェクトのクラスに対してcase ... whenを実行したい場合、これは動作しません

obj = 'Hi'case obj.classwhen String "It's a string"end

それは、String === Stringに変換されるからです。

デフォルトの演算子

casewhen String===演算子が使われるので、とても便利です。

しかし、別の演算子を使いたい場合もあります。 Rubyではそれが可能です。

casewhen a < 3 "Smaller than 3"end

Case is an expression

名前が示すように、全体が式です。 つまり、値に評価されるということです。 ですから、case式全体の結果を、次のように変数に代入することができます。

value = case when a < 3 "Smaller than 3" end

フォールスルーはありません

他の言語をお使いの方は、switchcasebreakのように流れを断ち切るキーワードを使っていないことに気づいたはずです。

それは、caseにはフォールスルーがないからです。

複数のマッチ

これまで、when句には1つの値しか使用していませんでした。

case awhen 1..3 "Small number"end

正規表現のマッチング

case 式を使って何にでもマッチさせることができます。 しかし、念のために言うと、正規表現やラムダにもマッチさせることができます。

even = ->(x) { x % 2 == 0 }case awhen even "It's even"when /^+$/ "It's an integer"end

独自の定義

あまり知られていないことですが、独自のコンパレータを定義することができます。

Text = Struct.new(:min_length) do def ===(string) string.size > min_length && string.is_a?(String) endendcase awhen Text.new(100) "It's text"end

上記の例では、acaseIt's text を返します。

Use polymorphism instead

OOP の利点についてはここでは説明しませんが、詳細は Object-Oriented Programming with Ruby の記事をご覧ください。

ケース編

class Person attr_reader :country def initialize(country) @country = country end def nationality case country when "USA" "This guy is an American" when "Romania" "This guy is a Romanian" end endendjohn = Person.new("USA")puts john.nationality # => This guy is an American

OOP編

class Person attr_reader :country def initialize(country) @country = country end def nationality country.nationality endendclass America def nationality "This guy is an American" endendclass Romania def nationality "This guy is a Romanian" endendjohn = Person.new(America.new)puts john.nationality # => This guy is an American

フロー制御のコードをできるだけ削除するのは良いアイデアです(すなわち、ifsやcase式など)をできるだけ削除するのが良いでしょう。 これにより、単一責任原則の遵守が向上し、一般的にプログラムがより読みやすくなります。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です