【Ruby】インスタンス変数について

スポンサーリンク

インスタンス変数についてまとめました。

インスタンス変数

@で始まる変数はインスタンス変数であり、カレントオブジェクトselfに属しています。初期化されていないインスタンス変数を参照した時の値はnilであり、存在も確認できません。普通のローカル変数の場合、初期化されてない変数を参照しようとすると NameError が発生するところが違います。

class MyClass
  def name=(value)
    @name = value
  end
  def name
    @name
  end
end

obj = MyClass.new
obj.instance_variables  #=> []
obj.name  #=> nil
obj.name = "hoge"  # @name が初期化された
obj.instance_variables  #=> [:@name]
obj.name  #=> "hoge"

変数と定数 - インスタンス変数

クラスインスタンス変数

インスタンス変数はカレントオブジェクトselfに属しているため、Class クラスのオブジェクトに属しているインスタンス変数のことをクラスインスタンス変数といいます。 クラスオブジェクトのインスタンス変数とクラスがインスタンス化されたオブジェクトのインスタンス変数は別物です。

class MyClass
  @name = "hoge"  # MyClassがselfになる
  def self.class_attribute
    @name
  end
  def name=(value)
    @name = value
  end
  def name
    @name
  end
end

MyClass.instance_variables  #=> [:@name]
MyClass.instance_variable_get(:@name)  #=> "hoge"
MyClass.class_attribute  #=> "hoge"

obj = MyClass.new
obj.name = "fuga"
obj.name  #=> "fuga"
MyClass.class_attribute  #=> "hoge"
obj.instance_variable_get(:@name)  #=> "fuga"
MyClass.instance_variable_get(:@name)  #=> "hoge"

attr_accessor / attr_reader / attr_writer

いわゆる getter や setter とよばれるインスタンス変数へのアクセサを定義するメソッド (クラスマクロ) がModule#attr_*で定義されています。

メソッド 機能
Module#attr_accessor インスタンス変数に対する読み取りと書き込みメソッドを定義する。
Module#attr_reader インスタンス変数の読み取りメソッドを定義する。
Module#attr_writer インスタンス変数への書き込みメソッドを定義する。

メソッドを使用するとアクセサのメソッドが定義されます。

class AccesorClass
  attr_accessor :name, :age
end
AccesorClass.public_instance_methods(false)  #=> [:name, :name=, :age, :age=]

class ReaderClass
  attr_reader :gender
end
ReaderClass.public_instance_methods(false)  #=> [:gender]

class WriterClass
  attr_writer :memo
end
WriterClass.public_instance_methods(false)  #=> [:memo=]

Module#attr_*で実際に定義されるのは以下のようなメソッドです。

def my_attribute=(value)
  @my_attribute = value
end

def my_attribute
  @my_attribute
end

初めは間違えやすいですが、例えば以下のようなインスタンスメソッドがあったとして、nameは変数を直接参照している訳ではなく、実はメソッドだということがわかります。

attr_accessor :name

def hello_method
  puts "hello #{name}!!"
end

クラスインスタンス変数を定義したい場合

クラスインスタンス変数へのアクセサを定義したい場合は特異クラスに記述します。

class MyClass
  class << self
    attr_accessor :name
  end
end
MyClass.name = "Bob"
MyClass.name  #=> "Bob"

インスタンス変数関連のメソッド

インスタンス変数を操作するためのメソッドには以下のようなものが存在します。

メソッド 機能
Object#instance_variables オブジェクトのインスタンス変数名を返す
Object#instance_variable_get オブジェクトの指定したインスタンス変数の値を取得して返す
Object#instance_variable_set オブジェクトの指定したインスタンス変数に値を設定する
Object#remove_instance_variable オブジェクトから指定したインスタンス変数を取り除き値を返す
Object#instance_variable_defined? 指定したインスタンス変数が定義されていたら真を返す
class Foo
  def intialize
    @name = 'taro'
  end
end

obj = Foo.new
obj.instance_variables  #=> [:@name]
obj.instance_variable_get(:@name)  #=> "bar"
obj.instance_variable_set(:@age, 30)  #=> 30
obj.instance_variables  #=> [:@name, :@age]
obj.remove_instance_variable(:@name)  #=> "bar"
obj.instance_variable_defined?(:@name)  #=> false
obj.instance_variable_defined?(:@age)  #=> true