ようへいの日々精進XP

よかろうもん

2018 年 01 月 05 日(金)

ジョギング

  • 朝は雨, お昼休みに走ろうと思ったけど雨, 今日は走るなってことでお休み
  • 右膝に違和感

日課

  • (腕立て x 40 + 腹筋 x 30) x 3

終日

  • 寒かった
  • 手足キンキン

特異クラスに出会う

Ruby の本を読んでいたら, 以下のようなコードに出会った.

class A
  @@x = 0
  class << self
    @@x = 1
    def x
      @@x
    end
  end
  def x
    @@x = 2
  end
end

class B < A
  @@x = 3
end

p A.x #=> 3  

p A.x がなぜ 3 が出力されるのか...

  • クラス変数 (@@x) はスーパークラス (A) とサブクラス (B) 間で共有されている為, 最終的にクラス変数には 3 が代入される
  • A.x クラスメソッド内で @@x が呼ばれてクラス変数を出力する

尚, A.x のクラスメソッドは self << class という特異クラス形式で定義(「特異メソッドという仕組みを使ってクラスメソッドを表現している」という表現が適切なようだ)されている. 特異クラスについては「るびま」の記事がとても参考になった.

上記のコードで B クラスを継承していない状態でクラスメソッド A.x を呼び出した場合にどうなるのか.

[1] pry(main)> class A
[1] pry(main)*   @@x = 0
[1] pry(main)*   class << self
[1] pry(main)*     @@x = 1
[1] pry(main)*     def x
[1] pry(main)*       @@x
[1] pry(main)*     end
[1] pry(main)*   end
[1] pry(main)*   def x
[1] pry(main)*     @@x = 2
[1] pry(main)*   end
[1] pry(main)* end
=> :x
[2] pry(main)> p A.x
1
=> 1

ちなみに, 上のコードで A クラスからインスタンスを生成して x メソッドを呼び出すとどうなるか.

[1] pry(main)> class A
[1] pry(main)*   @@x = 0
[1] pry(main)*   class << self
[1] pry(main)*     @@x = 1
[1] pry(main)*     def x
[1] pry(main)*       @@x
[1] pry(main)*     end
[1] pry(main)*   end
[1] pry(main)*   def x
[1] pry(main)*     @@x = 2
[1] pry(main)*   end
[1] pry(main)* end
=> :x
[2] pry(main)> foo = A.new
=> #<A:0x007ffceb9eb9f8>
[3] pry(main)> foo.x
=> 2

さらに, A クラスを継承した B クラスからインスタンスを生成するとどうなるか.

[4] pry(main)> class B < A
[4] pry(main)*   @@x = 3
[4] pry(main)* end
=> 3
[5] pry(main)> bar = B.new
=> #<B:0x007ffcec85b9c0>
[6] pry(main)> bar.x
=> 2

脱線したけど, 特異クラスや特異メソッドについて少しだけ垣間見れた気がした.