Help us understand the problem. What is going on with this article?

【まとめ】インスタンス変数、クラス変数、クラスインスタンス変数

More than 5 years have passed since last update.

すっかりPHP脳になっていたため、Ruby脳に切り替えるべくクラスに関わる変数まわりをおさらいした。

1. インスタンス変数

インスタンスごとに独立して持つ変数。

  • インスタンス変数にアクセスできるのは、initializeメソッドとオブジェクトのインスタンスメソッドだけ
  • initializeメソッドで初期化されて、その後各インスタンスメソッドから参照・変更される使い方が多い(と思う)
  • PHPやJavaみたいに事前にクラス定義内で定義する必要がない

1-1. 定義

変数名の前に「@」をつけて定義する

@instance_var = 'instance_var'

1-2. 使い方

class Foo
  # 明示的にインスタンス変数を宣言しなくて良い
  # => 宣言した場合、それは「クラスインスタンス変数」と見なされる

  # (o) initializeメソッドからアクセス
  def initialize
    @instance_var = 'instance_var'
    p "#{@instance_var} at initialize"
  end

  # (o) インスタンスメソッドからアクセス
  def xxx
    p "#{@instance_var} at xxx"
  end

  # (x) クラスメソッドからアクセス
  def self.yyy
    p @instance_var
  end
end

# initializeメソッドからはアクセスできる
foo = Foo.new # => 'instance_var at initialize'

# インスタンスメソッドからもアクセスできる
foo.xxx # => 'instance_var at xxx'

# クラスメソッドからはアクセスできない
Foo.yyy # => nil

2. クラス変数

そのクラスの全てのインスタンスで共有される変数

  • クラスとそのインスタンスがスコープになる
  • 定数と似ているがクラス変数は何度でも値を変更できる点で異なる
  • クラスメソッド、インスタンスメソッド、クラス定義式内でアクセス可能

2-1. 定義

変数名の前に「@@」をつけて定義する

@@class_var = 'class_var'

2-2. 使い方

class Foo
  @@class_var = 0

  def xxx
    @@class_var += 1
    p @@class_var
  end

  def self.yyy
    @@class_var += 1
    p @@class_var
  end
end

foo = Foo.new

# 同一インスタンス内で値は共有される
foo.xxx # => 1
foo.xxx # => 2

# インスタンスが異なっても、値は共有されている
foo2 = Foo.new
foo2.xxx # => 3

# クラスメソッドからもアクセスできるし、値も共有されている
Foo.yyy # => 4

3. クラスインスタンス変数

クラスオブジェクトのインスタンス変数
個人的に非常にややこしい。見た目はインスタンス変数なのに、機能的にはクラス変数に近いため。

  • 一見するとクラス変数とほぼ同じように使えるが、そのクラスのみでしか参照できない。例えば、そのクラスを継承したクラスではその変数にアクセスできない。
  • クラスメソッドからはアクセスできる
  • インスタンスメソッドからアクセスすることはできない(クラスオブジェクトのインスタンス変数であるため)
  • クラス定義式内で定義される(メソッド内で初期化されない)
  • 見た目は通常のインスタンス変数と同じため、混同されやすい

3-1. 定義

変数名の前に「@」をつけて定義する
※ 見た目はインスタンス変数と同じだが、定義する場所がクラス定義式内になる

@class_instance_var = 'class_instance_var'

3-2. 使い方

class Foo
  # クラス定義式内で定義される
  @class_instance_var = 'class_instance_var'

  # クラスメソッド内でクラスインスタンス変数を出力
  def self.xxx
    p @class_instance_var
  end

  # インスタンスメソッド内でクラスインスタンス変数を出力
  # => これはインスタンス変数扱いとなり、参照できない 
  def yyy
    p @class_instance_var
  end
end

# Fooを継承したBarクラスを作成
class Bar < Foo
end

# クラスメソッドからクラスインスタンス変数は参照できる
Foo.xxx # => 'class_instance_var'

# インスタンスメソッドからクラスインスタンス変数は参照できない
# => インスタンス変数とみなされるため
foo = Foo.new
foo.yyy # => nil

# 継承されたクラスからクラスインスタンス変数は参照できない
Bar.xxx # => nil
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away