その他
    ホーム 技術発信 DoRuby case文の落とし穴

    case文の落とし穴

    この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

    初めまして、エンジニア一年目のサンドリバー砂川です。

    今回は開発中につまずいたcase文の挙動について解説をします。

    こんな感じのcase文を考えてみます。

    class Obj
      class Foo
      end
    
      class Bar
      end
    end
    
    obj = Obj::Foo
    
    case obj
      when Obj::Foo
        puts "obj is Foo."
      when Obj::Bar
        puts "obj is Bar"
      else
        puts "obj is unknown...."
    end
    
    

    スクリプトを実行してみると

    obj is unknown....
    
    

    何故か比較がうまいこと出来てません。

    実はcase文ではこんな風に比較が行われます。

    case obj
      when Obj::Foo
    end
    ↓
    if Obj::Foo === obj
    
    

    問題は演算子===で、こいつは呼び出したオブジェクトの型によって挙動が変わります。

    例えばString#===なら==と同じ挙動ですが、Class#===の場合はkind_of?と同じ挙動になります。

    kind_of?メソッドは、引数が呼び出したオブジェクトのインスタンスの場合にtrueを返します。

    今回のコードではobj = Obj::Fooとクラスオブジェクト自体を代入していたのでfalseになってしまったんですね。

    なので解決策として、objにインスタンスを代入する。

    obj = Obj::Foo.new
    
    

    あるいはto_sメソッドを利用して比較する。

    case obj.to_s
      when Obj::Foo.to_s
        puts "obj is Foo."
      when Obj::Bar.to_s
        puts "obj is Bar"
      else
        puts "obj is unknown...."
    end
    
    
    obj is Foo.
    
    

    で解決です。