基礎

Rubyのクラス変数入門|@@で始まるクラス共有データの使い方

クラス変数はクラスのすべてのインスタンスで共有される変数です。@@で始まる名前で定義し、インスタンスの数を数えたり、クラス全体の設定値を管理するのに使います。インスタンス変数(@)が各インスタンスに固有なのに対し、クラス変数はクラス全体で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
ログレベル: debug

IDの自動採番

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採番、設定値の管理などに使える
  • インスタンス変数(@)は各インスタンスに固有、クラス変数(@@)は全体で共有
  • クラス変数は親クラスと子クラスで共有されるため注意が必要
  • 継承を使う場合はクラスインスタンス変数の方が安全