kiyokaのブログアーカイブ

Archive of old blog posts

Rubyのよくわからない挙動(1)

===メソッド(比較演算子)の挙動がよくわからない。

クラス A を定義し、インスタンスを a に代入する。

$ irb
>> class A ; end
class A ; end
=> nil
>> a = A.new
a = A.new
=> #<A:0x3637ec>

== がtrueになるのはわかる。

>> a.class == A
a.class == A
=> true

=== では何故falseになるのか。

>> a.class === A
a.class === A
=> false

=== がtrueになってくれないと === 演算子が適用される case 〜 when が使えない。 例えば、

  case val.class
  when Cell
    Cell型の場合の処理
  when Fixnum
    Fixnum型の場合の処理
  end

という記述はダメ。どれにもマッチしない。

こう書けばいけるけど、ちょっと苦しい。

  case val.class.to_s
  when "Cell"
    Cell型の場合の処理
  when "Fixnum"
    Fixnum型の場合の処理
  end

こんな場合Rubyの定石として、どう書くんだろう。


コメント by Grape:
勉強し始めたばかりなので、まだ何とも言えませんが、 Rubyの===は、「サブクラスで適宜再定義される」とあるので、オブジェクトによって挙動が違う可能性があります。 つまり、実装によっては必ずしも型が同じで値が同じ時にTrueという動きではないかもしれません。

的外れな答えでしたら、すみませんorz


コメント by mogya:
>こんな場合Rubyの定石として、どう書くんだろう。

こうらしいです。 case val when Cell Cell型の場合の処理 when Fixnum Fixnum型の場合の処理 end

[ruby-list:10473]case with Class からはじまる一連のスレッドに書いてありました。 http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-list/10473?10428-11968


コメント by kiyoka:
Grapeさん、mogyaさん、コメントどうもです。 mogyaさんに教えてもらった方法でいけそうです。 内部の仕組みはよくわかりませんが、これで短く書けますね。(そのへんがRubyに対して好みがわかれるところでしょうが…) 以下、実験結果です。

irb(main):001:0> class A ; end => nil irb(main):002:0> a = A.new => #<A:0x4023c478> irb(main):003:0> case a irb(main):004:1> when A irb(main):005:1> 1 irb(main):006:1> when B irb(main):007:1> 2 irb(main):008:1> else irb(main):009:1* 3 irb(main):010:1> end => 1

今作っているLispインタプリタをこのスタイルに直しておきますです。

コメント by Grape:
勉強し始めたばかりなので、まだ何とも言えませんが、 Rubyの===は、「サブクラスで適宜再定義される」とあるので、オブジェクトによって挙動が違う可能性があります。 つまり、実装によっては必ずしも型が同じで値が同じ時にTrueという動きではないかもしれません。

的外れな答えでしたら、すみませんorz

コメント by mogya:
>こんな場合Rubyの定石として、どう書くんだろう。

こうらしいです。 case val when Cell Cell型の場合の処理 when Fixnum Fixnum型の場合の処理 end

[ruby-list:10473]case with Class からはじまる一連のスレッドに書いてありました。 http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-list/10473?10428-11968