クラス変数はクラスのすべてのインスタンスで共有される変数です。@@で始まる名前で定義し、インスタンスの数を数えたり、クラス全体の設定値を管理するのに使います。インスタンス変数(@)が各インスタンスに固有なのに対し、クラス変数はクラス全体で1つだけ存在します。
基本的な使い方
Ruby
class User
@@count = 0 # クラス変数の初期化
def initialize(name)
@name = name
@@count += 1 # インスタンスが作られるたびにカウントアップ
end
def self.count
@@count
end
def info
"#{@name}(全ユーザー数: #{@@count})"
end
end
puts "初期ユーザー数: #{User.count}"
user1 = User.new('太郎')
user2 = User.new('花子')
user3 = User.new('次郎')
puts user1.info
puts "現在のユーザー数: #{User.count}"実行結果
初期ユーザー数: 0
太郎(全ユーザー数: 3)
現在のユーザー数: 3@@countはすべてのUserインスタンスで共有されています。User.newが呼ばれるたびに@@countが増加し、どのインスタンスからアクセスしても同じ値が見えます。
インスタンス変数との違い
Ruby
class Dog
@@total = 0 # クラス変数: 全体で共有
def initialize(name)
@name = name # インスタンス変数: 各インスタンスに固有
@@total += 1
end
def to_s
"#{@name}(犬の総数: #{@@total})"
end
end
dog1 = Dog.new('ポチ')
dog2 = Dog.new('タロウ')
dog3 = Dog.new('ハナ')
puts dog1 # @nameはインスタンスごとに異なる
puts dog2 # @@totalは全インスタンスで共通
puts dog3実行結果
ポチ(犬の総数: 3)
タロウ(犬の総数: 3)
ハナ(犬の総数: 3)クラス変数の実用例
設定値の管理
Ruby
class AppConfig
@@debug_mode = false
@@log_level = 'info'
def self.debug_mode=(value)
@@debug_mode = value
end
def self.debug_mode?
@@debug_mode
end
def self.log_level
@@log_level
end
def self.log_level=(value)
@@log_level = value
end
def self.status
puts "デバッグモード: #{@@debug_mode}"
puts "ログレベル: #{@@log_level}"
end
end
AppConfig.status
puts '---'
AppConfig.debug_mode = true
AppConfig.log_level = 'debug'
AppConfig.status実行結果
デバッグモード: false
ログレベル: info
---
デバッグモード: true
ログレベル: debugIDの自動採番
Ruby
class Article
@@next_id = 1
attr_reader :id, :title
def initialize(title)
@id = @@next_id
@@next_id += 1
@title = title
end
def to_s
"記事##{@id}: #{@title}"
end
end
a1 = Article.new('Ruby入門')
a2 = Article.new('Rails入門')
a3 = Article.new('テスト入門')
puts a1
puts a2
puts a3実行結果
記事#1: Ruby入門
記事#2: Rails入門
記事#3: テスト入門継承時のクラス変数の挙動
Ruby
class Animal
@@count = 0
def initialize
@@count += 1
end
def self.count
@@count
end
end
class Cat < Animal
end
class Dog < Animal
end
Animal.new
Cat.new
Cat.new
Dog.new
# クラス変数は親子クラスで共有される!
puts "Animal: #{Animal.count}"
puts "Cat: #{Cat.count}"
puts "Dog: #{Dog.count}"実行結果
Animal: 4
Cat: 4
Dog: 4クラス変数は親クラスと子クラスの間で共有されるため、すべてのクラスで同じ値(4)が表示されます。
クラスインスタンス変数という選択肢
クラス変数の代わりにクラスインスタンス変数(@変数をクラスレベルで使う)を使う方法もあります。クラスインスタンス変数は継承時に子クラスと共有されないため、より安全です。
継承時の注意点
クラス変数は親クラスと子クラスで共有されるため、子クラスでの変更が親クラスにも影響します。これは意図しないバグの原因になりやすいです。継承を使う場合はクラスインスタンス変数の利用を検討しましょう。
まとめ
- クラス変数は
@@で始まり、クラスのすべてのインスタンスで共有される - インスタンスのカウント、ID採番、設定値の管理などに使える
- インスタンス変数(
@)は各インスタンスに固有、クラス変数(@@)は全体で共有 - クラス変数は親クラスと子クラスで共有されるため注意が必要
- 継承を使う場合はクラスインスタンス変数の方が安全