Rubyのクラス変数とは何か【@@で始まるやつ】
Railsのソースコードを見ていると、@@
で定義されたクラス変数を見かけることがある。クラス変数とは、文字通りクラスの中で定義する変数を指す。これは挙動を1つずつ見ていくと理解しやすい。
以下では@@name
というクラス変数を定義している。
class Parent
@@name = "Denji"
# クラス変数を返すメソッド
def self.name
@@name
end
end
クラス変数を取得してみる。
# クラス変数の値が返る
p Parent.name #=> "Denji"
コード見たままだが、クラス変数が返る。
では次に、サブクラスを作ってみる。
class Parent
@@name = "Denji"
def self.name
@@name
end
end
# サブクラスを作成
class Child < Parent
end
この状態で、それぞれのクラスからクラス変数を参照するとどうなるか?
p Parent.name #=> "Denji"
p Child.name #=> "Denji"
Parentクラスを継承したChildクラスで、@@name
クラス変数を参照できているのがわかる。
それでは次に、サブクラス側でクラス変数に値を代入してみるとどうなるか?
class Parent
@@name = "Denji"
def self.name
@@name
end
end
class Child < Parent
# サブクラスで値を代入する
@@name = "Pochita"
end
するとこうなる。
p Parent.name #=> "Pochita"
p Child.name #=> "Pochita"
サブクラス側で新たな値をクラス変数に代入したところ、親クラス側でも同様の値になっていることがわかる。
では、さらにサブクラスのメソッドでクラス変数に値を代入するとどうなるか?
class Parent
@@name = "Denji"
def self.name
@@name
end
end
class Child < Parent
@@name = "Pochita"
# 値を代入する
def self.name
@@name = "Makima"
end
end
するとこうなる。
p Parent.name #=> "Pochita"
p Child.name #=> "Makima"
さきほどと同様に、サブクラスの冒頭でクラス変数に新たな値を代入しているため、親クラスではPochita
になっている。
しかし、サブクラスのメソッドではMakima
に変わっている。代入ができている。これは数値にするとわかりやすい。
class Parent
@@number = 1
def self.number
@@number
end
end
class Child < Parent
@@number += 1
def self.number
@@number += 1
end
end
p Parent.number #=> 2
p Child.number #=>
サブクラス側の冒頭で@@number
に1を新たに+しているので、Parent.number
が2になっている。
そして、サブクラスのself.number
メソッド内でさらに1を+していて、@@number
は3となっている。
なお、今回のコードではクラスメソッドでクラス変数を参照しているが、インスタンスメソッドからでも参照・代入が可能だ。
class Parent
@@name = "Denji"
def self.name
@@name
end
end
class Child < Parent
@@name = "Pochita"
def name
@@name = "Makima"
end
end
p Parent.name #=> "Pochita"
# インスタンスメソッドからでもクラス変数を参照・代入できる
p Child.new.name #=> "Makima"
最後に、変数と定数 (Ruby 3.2 リファレンスマニュアル)にわかりやすい解説があるので引用させていただく。
クラス変数と定数の違い
再代入可能(定数は警告を出す)
クラスの外から直接参照できない(継承されたクラスからは参照/代入可能)
クラス変数とクラス自身のインスタンス変数の違い
サブクラスから参照/代入が可能
インスタンスメソッドから参照/代入が可能
Discussion