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

カレントオブジェクトselfについて Ruby

More than 5 years have passed since last update.

Rubyのプログラムの実行は常にオブジェクトをかいして行われていて、メソッドが呼び出されるとレシーバはselfになる。カレントオブジェクトはカレントクラスのインスタンスである。

下記のコードを見てほしい。

> [1,2,3].map(&:even?)

=> [false, true, false]

以下のコードを打った時にこのオブジェクトのレシーバはArrayのクラスのインスタンスであるがselfに着目して言えばレシーバであるオブジェクトがカレントオブジェクトであり、カレントクラスのインスタンスである。

selfはRubyプログラムのなかに同時に複数存在しない。

クラス定義のメソッド定義の中で実行してみる

class Cat

  def where_self
    self
  end
end

Cat.new.where_self

=> #<Cat:0x007f8c03205440>

Catクラスのインスタンスが返ってくる。

名前空間で実行してみる

module Zoo
  class Cat
    def where_self
      self
    end
  end
end
Zoo::Cat.new.where_self

=> #<Zoo::Cat:0x007f8c02bf4f10>

Zoo::Catクラスのインスタンスが返ってくる。

interactive ruby、略してirbで実行してみる

> self
=> main

mainというオブジェクトが返ってきた、これはどういう意味か?
mainのクラスを調べてみれば分かる。

> self.class
=> Object

mainはObjectのインスタンスであるようだ、
irbはオブジェクトの内部がmainに属していてそこでメソッド等が実行されているようだ。

クラスメソッドを定義する時にselfにドットをつけて定義していた。

class Cat
  def self.class_method
    "class_method"
  end
end

newなどのクラスメソッドを使ってインスタンス化してオブジェクトを生成するがクラス自身もオブジェクトになれて、
このselfはクラス名を指していてクラス定義にselfが使われるときはクラス名を指す。

これを知っておくとインスタンス変数とクラスインスタンス変数を区別できるようになる。

selfはオブジェクトを指すがクラス定義ではクラス名を指し以下のコードに着目して欲しい。

class Cat
  @siro = "kuro"
  attr_reader :siro

  def initialize(siro="siro")
    @siro = siro
  end

  def self.kuro
    @siro
  end
end

a = Cat.new
a.siro
=> "siro"
Cat.siro
=> "kuro"

同じ@siroのインスタンス変数だが違う値が入っている。
aオブジェクトがselfとなるインスタンス変数かCatがselfとなるインスタンス変数がある、後者をクラスインスタンス変数という。

selfへの理解があればeval属性のinstance_evalやclass_evalなどの理解にも役に立つ。

instance_evalとは?

selfに変更を加えることができるメソッド

class Cat
  def initialize(cat="siro")
    @cat = cat
  end

  def value
    @cat
  end
end

a = Cat.new
a.value
# => "siro"

a.instance_eval do 
  @cat = "kuro"
end

a.value
# => "kuro"

オブジェクトはクラスの参照とインスタンス変数をもつ、本来であればクラス定義でattr_accessorとかメソッドを定義して値の有無を制御するがこのメソッドを使えばオブジェクトのカプセル化を壊せる。
上の例ではオジェクトがもつインスタンス変数に"kuro"という値を格納している。

class_evalとは?

selfに変更を加えることでき、なおかつ、カレントクラスをオープンしてクラス定義の外からクラスに変更を加えることができる

class Cat
  def kuro
    "kuro"
  end
end

Cat.class_eval do
  def siro
    "siro" 
  end
end

a = Cat.new
a.siro
# => "siro"

クラスを内部からではなく、外部からクラスのメソッドを定義する。

まとめ

カレントオブジェクトのselfは現在のオブジェクトを指し、同時に複数存在できない。

カレントオブジェクトの所属するクラスをカレントクラスという。

instance_evalを使えばselfに変更を加えることができる

class_evalを使えばselfとカレントクラスに変更を加えることができる

続く、、、、

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
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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
ユーザーは見つかりませんでした