406
332

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2013-12-24

概要

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

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

2つのルール

  1. privateメソッドを呼び出す時は、レシーバは指定できない
  • 自分(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メソッドはサブクラスからも呼び出すことが出来る

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

406
332
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
406
332

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?