インスタンス変数
インスタンス変数は「@
」で始まる名前をしています。
インスタンス単位で持つ変数です。
class C
def foo
@count ||= 0
@count += 1
if @count < 3
puts "foo は呼ばないでください."
else
puts "foo は呼ぶなッ!!#{@count} 度目!!"
end
end
end
c1 = C.new
c1.foo
c1.foo
c1.foo
puts '-' * 8
c2 = C.new
c2.foo
c2.foo
c2.foo
実行結果
$ ruby sample-ivar.rb
foo は呼ばないでください.
foo は呼ばないでください.
foo は呼ぶなッ!!3 度目!!
--------
foo は呼ばないでください.
foo は呼ばないでください.
foo は呼ぶなッ!!3 度目!!
c1 も c2 もそれぞれ 3度目でキレます。
クラス変数
クラス変数は「@@
」で始まる名前をしてます。
クラス単位で持つ変数です。
class C
def foo
@@count ||= 0
@@count += 1
if @@count < 3
puts "foo は呼ばないでください."
else
puts "foo は呼ぶなッ!!#{@@count} 度目!!"
end
end
end
c1 = C.new
c1.foo
c1.foo
c1.foo
puts '-' * 8
c2 = C.new
c2.foo
c2.foo
c2.foo
実行結果
$ ruby sample-cvar.rb
foo は呼ばないでください.
foo は呼ばないでください.
foo は呼ぶなッ!!3 度目!!
--------
foo は呼ぶなッ!!4 度目だ!!
foo は呼ぶなッ!!5 度目だ!!
foo は呼ぶなッ!!6 度目だ!!
c2 は最初からキレまくりです。(クラス通算3度目以降はキレます)
継承に関わるアレコレ
module M0
@@v = :M0
def foo ; "I am 'M0'" ; end
end
module MM
@@v = :MM
def foo ; "I am 'MM'" ; end
end
module M
include MM
@@v = :M
def foo ; "I am 'M'" ; end
end
module PM
@@v = :PM
def foo ; "I am 'PM'" ; end
end
class A
include M0
@@v = :A
def foo ; "I am 'A'" ; end
end
class B < A
@@v = :B
def foo ; "I am 'B'" ; end
end
class C < B
@@v = :C
def foo ; "I am 'C'" ; end
end
class D < C
include M
prepend PM
@@v = :D
def foo ; "I am 'D'" ; end
def getv
@@v
end
end
d = D.new
p d.class.ancestors #=> [PM, D, M, MM, C, B, A, M0, Object, Kernel, BasicObject]
p d.getv
p d.foo
上のスクリプトを実行すると以下のようになります。
$ ruby sample.rb
[PM, D, M, MM, C, B, A, M0, Object, Kernel, BasicObject]
:D # メソッド getv の出力
"I am 'PM'" # メソッド foo の出力
(もっともな話ですが) foo の出力は予想通りでした。
現在は PM の foo が呼ばれていますが、それをコメントアウトすると次は D の foo が呼ばれます。
それをコメントアウトすると次は M の.....としていくと継承順(下図の緑線)をたどって最後は M0 の foo が呼ばれます。
継承関係図を以下に示します。(青箱:クラス、橙二重線箱:モジュール、緑線:ancestors、青線:superclass)
対して、「@@v
」の値を出力する getv ですが、現在は D の@@v
を参照しています。
これをコメントアウトすると......とやってみると以下の順番になります。
D -> C -> B -> A -> M0 -> M -> MM -> PM # クラス変数参照の順番
(これは図示しません。図を作ると美しくない図になります)
なんとなく、superclass をたどって折り返して来てインクルードされているモジュールを探索...、というようになっているようで、Ruby の仕様としては決まっているかも知れませんが、深く探求しません。
クラス変数に関しても、継承は複雑な問題をはらむようです。(で、強引にまとめます)
おわりに
本稿内容の動作確認は以下の環境で行っています。
- Ruby 2.1.5 p273
付録
上の継承図のソース(Graphviz DOT形式)
digraph {
rankdir=LR;
node [shape = box];
node [color = blue] A B C D;
node [color = orange, peripheries = 2] M0 M MM PM;
D [style = filled, fillcolor = cyan];
D -> C [color = blue];
C -> B [color = blue];
B -> A [color = blue];
PM -> D [color = green];
D -> M [color = green];
M -> MM [color = green];
MM -> C [color = green];
C -> B [color = green];
B -> A [color = green];
A -> M0 [color = green];
}