k-tokitoh

2019-11-30

クラス変数とインスタンス変数

職場で「クラス変数とクラスインスタンス変数の違い」が話題にあがっていて、以前理解したよな、と思いつつ咄嗟に整理して述べられないなと思ったので、思い出しつつまとめてみる。

基本的にはクラス変数とインスタンス変数というものがある。

まずサンプルコード。

class Parent
  @@var = 'class variable of Parent'
  @var = 'instance variable of Parent (so called class instance variable)'

  class << self
    def at_at_var
      @@var
    end

    def at_var
      @var
    end
  end

  def initialize
    @var = 'instance variable of parent'
  end

  def at_at_var
    @@var
  end

  def at_var
    @var
  end
end

インスタンス変数とは

あるインスタンスにおいて利用できる。@{変数名}により指示される。

たとえば、parent という「Parent クラスのインスタンス変数をもっている。

parent = Parent.new
parent.at_var  # => "instance variable of parent"

同様に、Parent という「Class クラスのインスタンス変数をもっている。

Parent.at_var # => “instance variable of Parent (so called class instance variable)”

後者のように「Class クラスのインスタンス変数」と呼ぶことがある。

クラス変数とは

あるクラスが保持する変数。@@{変数名}により指示される。

当然ながら Parent クラスは自身のクラス変数を利用できる。

Parent.at_at_var  # => "class variable of Parent"

クラス変数はこれに加えて、以下の特徴をもつ。

1. Parent クラスのインスタンスから、Parent クラスのクラス変数にアクセスできる
parent.at_at_var  # => "class variable of Parent"
2. Parent クラスを継承した Child クラスから、継承元である Parent クラスのクラス変数にアクセスできる
class Child < Parent
  def initialize
    @var = 'instance variable of child'
  end
end
Child.at_at_var  # => "class variable of Parent"
3.

(上記の合わせ技として)Parenet クラスを継承した Child クラスのインスタンスから、Child クラスの継承元である Parent のクラス変数にアクセスできる

child = Child.new
child.at_at_var  # => "class variable of Parent"

おまけ

仕組みはこれだけだと思う。最後に念のため、上で述べたクラス変数の「色んなところからアクセスできる性質」は、クラスインスタンス変数には与えられていないことを確認する。

1. Parent クラスのインスタンス変数にはアクセスできない
parent.at_var  # => "instance variable of parent"

@var は parent のインスタンス変数を指してしまっている。

2. Parent クラスを継承した Child クラスから、継承元である Parent クラスのクラスインスタンス変数にはアクセスできない
Child.at_var  # => nil

@var は「Child という Class クラスのインスタンス変数」を指してしまっている。(これは宣言していないのでnilが返っている。)

3. Parenet クラスを継承した Child クラスのインスタンス変数にはアクセスできない
child.at_var  # => "instance variable of child"

@var は child のインスタンス変数を指してしまっている。

丁寧にインスタンス変数」とか、どうしても早口言葉っぽくなるな…。

以上です。