Rubyには同じクラスから作られたインスタンスと、そのクラスを継承したクラスから作られたインスタンスから参照できるクラス変数を利用できます。
グローバル変数のように広い範囲で利用でき、それでいて関係ない場所から参照できないため、共通に適用したい値を格納したい変数として便利です。今回はRubyのクラス変数の使い方を紹介します。
Rubyで使える変数の種類
Rubyには参照範囲の違いにより4種類の変数があり、それぞれ変数名のつけ方が決まっています。その中でもクラス変数が参照できる範囲は特殊なので、使い方が解りにくいかもしえません。まずは4つの変数の違いについて紹介します。
Rubyでは4種類の変数が使える
Rubyでは、ローカル変数、インスタンス変数、クラス変数、グローバル変数の4種類の変数が使えます。それぞれ参照範囲が違っており、例えばローカル変数はメソッドの中でしか使えませんが、グローバル変数はプログラムのどこからでも参照可能です。また、それぞれの変数の書き方も決まっています。
次に4種類の変数における書き方と参照範囲を紹介します。
Rubyの変数の種類
- ローカル変数
小文字または`_’で始まる変数です。ブロック内またはメソッド定義内でしか参照されません。 - インスタンス変数
‘@’で始まる変数です。newメソッドで作成したインスタンスの中に限って参照でき、そのインスタンスの外からは参照されません。 - クラス変数
‘@@’で始まる変数です。インスタンス変数と似ていますが、同じクラス定義で作成したインスタンスで共通に使える変数です。今回、この変数の使い方を紹介します。 - グローバル変数
$で始まる変数です。プログラムのどこからでも参照できます。
変数の参照範囲を使われ方
プログラムの中では多くの変数が使われますが、その変数がどの範囲で使えるかは重要です。昔使われたプログラム言語の中には、全ての変数がプログラムのどこからでも参照できる仕様だったことから、メンテナンスが難しく、使われなくなったものさえありました。
今使われているプログラミング言語では、変数が参照できる範囲をできるだけ狭くし、共通で使える変数を特別な変数として扱うのが基本です。
例えば、Rubyのローカル変数は最もよく使われる変数ですが、メソッドの中やブロックの中でしか使えません。メソッドで計算して結果を他の場所で使う場合は、広く参照できる変数ではなく戻り値を利用することでシンプルな解りやすいプログラムを作れます。
また、オブジェクト内で共通に使う定数などはインスタンス変数やクラス変数など、参照範囲の広い変数を利用します。逆にプログラムのどこからでも参照できるグローバル変数は、システム全体に関わる特別な場合でのみ利用するのが一般的です。
クラス変数の基本と使い方
先ほど紹介したようにクラス変数は同じクラス定義で作成したインスタンス、およびそのクラスを継承したクラスから作られたインスタンスで共通に使える変数です。次からクラス変数の基本と使い方について紹介します。
クラス変数の書き方
クラス変数を利用する場合、変数名にアットマークを2つ続けた「@@」を付けて定義します。なおアアットマークが1つの「@」を付けた変数はインスタンス変数です。
クラス変数の書き方
@@変数名
クラス変数の例
@@class_n = 1 @@class_s = 'class variable'
クラス変数の参照範囲
クラス変数は、クラス定義の中で宣言され、そのクラス定義で作られたインスタンス、およびそのクラスを参照したクラスから作られたインスタンスから参照できる変数です。
インスタンス変数と似ていますが、その参照範囲が違います。インスタンス変数の参照範囲はクラス定義から作られたインスタンスの中に限られます。しかしクラス変数は、同じクラス定義から作られたインスタンスに限り、別のインスタンスからでも参照できます。
つまり、同じクラス定義から複数のインスタンスから共通して参照される定数のようなデータの格納先として利用できます。
サブクラスも参照範囲に含まれる
Rubyのようなオブジェクト指向言語の特徴は、定義してあるクラスを利用し、新しい機能を追加したクラスを作れる点です。基になったクラスをスーパークラスと呼び、それを基に新しい機能を追加したクラスをサブクラスと呼びます。
そして今回紹介しているクラス変数の参照範囲はクラスから作られたインスタンスの他に、サブクラスから作られたインスタンスも含みます。
もしサブクラスの中で新しいクラス変数を使う場合、スーパークラスのクラス変数と同じものを使うと、スーパークラス側のクラス変数を上書きしてしまいます。サブクラスを利用する場合、クラス変数の有無に注意してください。
クラス変数の利用例
先ほど紹介したようにクラス変数は、同じクラス定義から作られたインスタンスとそのクラスを継承したクラスから作られたインスタンス間で共通に参照できる変数です。
次に、インスタンス変数と比較した例と、複数のインスタンスで書き換えした場合の動作の例を紹介します。
クラス変数とインスタンス変数を比較した例
クラス変数「@@c_name」とインスタンス変数「@arg」は同じクラスで同時に使えます。下記の例では同じクラス定義から「obj1」と「obj2」の2つのインスタンスを作っていますが、「obj1」のクラス変数を変更すると、「obj2」からもその変更後の値を参照できます。
クラス変数を使った例
class Class_A @@c_name = "未定義" def initialize(arg1) @arg = arg1 end def set_c(name) @@c_name = name end def show_i() @arg end def show_c() @@c_name end end obj1 = Class_A.new("No.1") p obj1.show_i() # "No.1"が表示される p obj1.show_c() # "未定義"が表示される obj2 = Class_A.new("No.2") p obj2.show_i() # "No.2"が表示される p obj2.show_c() # "未定義"が表示される obj1.set_c("設定済") p obj1.show_c() # "設定済"が表示される p obj2.show_c() # obj1で設定した"設定済"が表示される
クラス変数を別のインスタンスが上書きする例
インスタンス作成時にinitializeメソッドを使用することで、インスタンスで共通に使う定数などを設定できるので、Rubyのプログラムではよく使われます。通常はインスタンス変数を利用しますが、この代わりにクラス変数を定義することも可能です。
ただしinitializeメソッドの中でクラス変数を設定するとインスタンスを作成する度にクラス変数が書き換えられるので注意してください。
インスタンス作成時にクラス変数を定義する例
class Class_B def initialize(arg1) @@c_name = arg1 end def show_c() @@c_name end obj1 = class_a.new("No.1") obj2 = class_a.new("No.2") obj3 = class_a.new("No.3") p obj3.show_c() # "No.3"が表示される
上記の例では、インスタンス作成時にクラス変数「@@c_name」がnewメソッドで指定した文字列に書き換えられます。そしてobj1、obj2、obj3の3つのインスタンスで同じクラス変数を書き換えることから「@@c_name」には、3番目の”No.3″が代入されています。
クラス変数が書き換わらない例
先ほど、クラス定義のinitializeメソッドによりクラス変数が書き換えられる例を紹介しましたが、クラス内で代入を定義しただけでは書き換わらないケースもあります。
例えば下記のようにクラスの中で「@@c_name = “未定義”」と宣言した場合、obj1でクラス変数「@@c_name」を書き換えた後で、obj2を作っても「@@c_name = “未定義”」は実行されません。既にobj1で書き換えられた値が格納されています。
class Class_C @@c_name = "未定義" def set_c(arg1) @@c_name = arg1 end def show_c() @@c_name end end obj1 = Class_C.new obj1.set_c("設定済") p obj1.show_c() # "設定済"が表示される obj2 = Class_C.new p obj2.show_c() # "未定義"ではなく"設定済"が表示される
まとめ
これまで紹介したようにクラス変数は、同じクラス定義から作られたインスタンスとそのクラスを継承したクラスから作られたインスタンス間で共通に参照できる変数です。
「@@」が付いた変数名を使うことから他の変数と区別しやすく、インスタンス間で共通に利用する値を格納する変数として使えます。便利な変数なので、ぜひ、Rubyのプログラムで利用してください。