概要
- Rubyのprivateメソッドを支える、2つのルール
- ルールを知る事によるメリット
※前者はメタプログラミングRubyより。
2つのルール
- 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メソッドはサブクラスからも呼び出すことが出来る
ことは至極当然なものとして頭に入ってくるのではないでしょうか。