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

[Ruby] privateメソッドの本質とそれを理解するメリット

More than 5 years have passed since last update.

概要

  • Rubyのprivateメソッドを支える、2つのルール
  • ルールを知る事によるメリット

※前者はメタプログラミングRubyより。

2つのルール

  1. privateメソッドを呼び出す時は、レシーバは指定できない
  2. 自分(self)以外のオブジェクトのメソッドを呼び出すには、レシーバを指定する必要がある

ルール1

privateのついたメソッドを呼び出す時は、レシーバは指定できない

例として、レシーバ指定しないパターンと、
明示的にレシーバ指定してしまうパターンを試してみます。

class Sample1

  def s1_call_private
    s1_private    # 通常の呼び出し
  end

  def s1_call_private_with_receiver
    self.s1_private    # あえてレシーバ(self)を明示して指定
  end

  private

    def s1_private
      p "Welcome to my private room!"
    end

end

s1 = Sample1.new

s1.s1_call_private
=> "Welcome to my private room!"

s1.s1_call_private_with_receiver
=> NoMethodError: private method `s1_private' called for..

ルール通り、レシーバを明示した方(s1_call_private_with_receiver)はNoMethodErrorが出る。

ルール2

自分(self)以外のオブジェクトのメソッドを呼び出すには、レシーバを指定する必要がある

※こちらは「privateメソッドのためのルール」という訳ではなく、至極当然の話ですが

class Sample2

  def s2_call_sample1
    s1 = Sample1.new
    s1.s1_call_private    # 通常の呼び出し
  end

  def s2_call_sample1_without_receiver
    s1 = Sample1.new
    s1_call_private    # レシーバ(s1)なしで呼んでみる
  end

end

s2 = Sample2.new
s2.s2_call_sample1
=> "Welcome to my private room!"

s2.s2_call_sample1_without_receiver
=> NameError: undefined local variable or method `s1_call_private' for..

当たり前ながらs2_call_sample1_without_receiverはエラー。

ここで、ルール1とルール2のコンフリクトが起きる。

つまり、
外部(s2)からs1のメソッドを呼び出そうとするなら、
s1.s1_privateのようにs1というレシーバをつける必要があるが(ルール2)、
(s1の)privateメソッドはレシーバを付けて呼び出す事を許してくれない(ルール1)。

コードに示すと以下になります。

class Sample2

  def s2_call_sample1_private
    s1 = Sample1.new
    s1.s1_private    # 外部s1のメソッドを呼びたいので、レシーバs1は必須(ルール2)。
                     # でもprivateメソッドなのでレシーバは付けられない(ルール1)。
  end

end

結果として、privateメソッドは外部から呼び出すことが出来ない

これがprivateメソッドの内部的な仕組みです。

つまり

Rubyのprivateメソッドは、

  • 呼び出す際にレシーバを指定できない

(し、逆にそれ以外は「ごく普通のメソッド」だと言える)

このことを理解しておくメリット

privateの挙動の混乱を防ぎやすい。

例えば、
JavaやC#の常識が通用しないRubyのprivateメソッド
http://blog.jnito.com/entry/20120315/1331754912

上記記事にもあるように、JavaやC#と違いRubyは

スーパークラスのprivateメソッドはサブクラスからも呼び出すことが出来る。

これは定義だけ覚えているとすぐに分からなくなりそうですが、

privateメソッドは呼び出す際にレシーバを指定できない(だけ)

という今回学んだルールと、

サブクラスからなら、スーパークラスのメソッドはレシーバを指定せずに呼び出せる

という(ごく当たり前の)決まりを掛け合わせて考えれば、

スーパークラスのprivateメソッドはサブクラスからも呼び出すことが出来る

ことは至極当然なものとして頭に入ってくるのではないでしょうか。

Why do not you register as a user and use Qiita more conveniently?
  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
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