Rubyでのインスタンス変数とクラス変数の扱いについて
いきなりコード。
class Access
def initialize
# インスタンス変数を初期化
@instance = "Access instance var"
# クラス変数を初期化
@@class = "Access class var"
end
def self.test
p @instance
p @@class
end
def test
p @instance
p @@class
end
end
obj = Access.new
p "--CLASS--"
Access.test
p "--INSTANCE--"
obj.test
実行結果がこちら
"--CLASS--"
nil
"Access class var"
"--INSTANCE--"
"Access instance var"
"Access class var"
解説
上記のコード内では、
- Accessクラス定義
- initializeメソッド定義
- testメソッド(クラスメソッド)定義
- testメソッド(インスタンスメソッド)定義
- Accessクラスのオブジェクト作成
- Accessオブジェクトからtestメソッド呼び出し
- オブジェクトからtestメソッド呼び出し
という処理を行っています。
Accessクラスのオブジェクトを生成したタイミングで、initializeメソッドにより、インスタンス変数とクラス変数をそれぞれ初期化されます。
それぞれのメソッド内では、初期化したインスタンス変数とクラス変数を呼び出していますが、クラスメソッド内で呼び出したインスタンス変数がnilを返しています。
Rubyのインスタンス変数はそのクラスのオブジェクトごとに別々の値を持ちます。
Rubyはクラスもオブジェクトの一種です。
コード内のself.testメソッド
はAccessオブジェクトの特異メソッドという扱いになり、特異メソッド内で呼ばれるインスタンス変数は、Accessオブジェクト内のスコープに属しています。
そのため、クラスメソッド内で呼ばれたインスタンス変数は初期化されていないため、nilを返したというわけです。
ためしに、クラスメソッド内でインスタンス変数を初期化してみます。
class Access
def initialize
# インスタンス変数を初期化
@instance = "Access instance var"
# クラス変数を初期化
@@class = "Access class var"
end
def self.test
@instance = "Access class instance var"
p @instance
p @@class
end
def test
p @instance
p @@class
end
end
obj = Access.new
p "--CLASS--"
Access.test
p "--INSTANCE--"
obj.test
実行結果はこちらです。
"--CLASS--"
"Access class instance var"
"Access class var"
"--INSTANCE--"
"Access instance var"
"Access class var"
クラス内で同じインスタンス変数を用いていますが、別々の値を表示しており、変数のスコープがことなっていることがわかります。
一方、クラス変数は、そのクラスやそのクラスに紐付いたオブジェクトから共通に呼び出すことができるため、問題なく表示されています。