「privateメソッドって外から呼び出せないやつでしょ?」「レシーバを指定して呼び出せないんでしょ?」から抜け出すべく色々試してみた。
※2.7以降はレシーバにselfをとれるようになったようなのでバージョンを変えて検証してみた。
試してみる
$ rbenv local 2.4.3
class A def call_private a_private end private def a_private p "this is a_private method" end end a = A.new a.call_private a.a_private # 外からは呼び出せない
"this is a_private method" Sample.rb:15:in `<main>': private method `a_private' called for #<A:0x00007f90360f57d0> (NoMethodError)
「外から呼び出そうとするとエラーになる」。これが今までの理解
レシーバを指定できない?
privateメソッドを呼び出すときにレシーバを指定してみると
class A def call_private p self a_private end def call_private_with_reciever p self self.a_private end private def a_private p "this is a_private method" end end a = A.new a.call_private a.call_private_with_reciever
#<A:0x00007ff5709c4da8> "this is a_private method" #<A:0x00007ff5709c4da8> Sample.rb:9:in `call_private_with_reciever': private method `a_private' called for #<A:0x00007ff5709c4da8> (NoMethodError)
やろうとしていることは同じだけど、レシーバがある場合はエラーになる。
Ruby2.7以降で検証
2.7以降ではselfの指定をしてもエラーにならない。
#<A:0x00007f8ea8967c18> "this is a_private method" #<A:0x00007f8ea8967c18> "this is a_private method"
クラスの中でレシーバを指定
クラス内部ではレシーバを指定しないとクラスメソッドとして認識されてしまうはずなのでどうなるのだろうと思い、
クラスの中でインスタンスを作成して、レシーバを指定した状態で直接privateメソッドを呼び出してみた
class A def call_private a_private end def a_private p "this is a_private method" end a = A.new a.a_private # クラスの中でレシーバを指定 private :a_private end a = A.new a.a_private # 外からは実行できない
"this is a_private method" Sample.rb:17:in `<main>': private method `a_private' called for #<A:0x00007fba8c8f11c0> (NoMethodError)
問題なく実行できた。
「レシーバを指定できない」というわけではなさそう。
まとめ
以前は「privateメソッドはレシーバを指定できないので、結果的に外部から呼び出しができない」という理解だったが、クラス内部で呼び出す場合は(レシーバがないとクラスメソッドとして認識されてしまうので)当然レシーバが必要だし、Ruby2.7以降ではインスタンスメソッドの中でselfを使ってもエラーにならない。