privateメソッドのルール
『メタプログラミングRuby』P.65のコラムに、privateメソッドのルールについて書かれていました。
”プライベートメソッドには1つのシンプルなルールが適用される。それは、「明示的なレシーバをつけてプライベートメソッドを呼び出すことはできない」というものだ。つまり、プライベートメソッドは、暗黙的なレシーバselfに対するものでなければならない。”
「privateメソッドは、明示的なレシーバをつけられない」。
レシーバがない状態といえば、「(暗黙的に)selfをレシーバとする状態」しかないわけですから、
通常はそのprivateメソッドを持っているオブジェクトからじゃないとメソッドを参照する経路がありません。
これによってRubyのprivateメソッドが「プライベートな」存在になるのですね。
(本気を出せば破ってしまえますが、それはまた別の話。)
これはわかりやすい覚え方です。
具体的に、極端な例を試してみると以下のようになります。
class A def foo self.bar end private def bar puts "bar is private method" end end A.new.foo # => error
例え同じクラス内からでも、明示的にレシーバ(ここではself)を
書いてしまうとエラーが起きます。
ルールの例外
しかし、このルールには例外が一つあります。それは「セッターメソッドには明示的なレシーバが必要」、ということです。
(セッターメソッドというのは、メソッド名が「=」で終わるもののこと)
先程の例を、privateメソッドをセッターメソッドに変えてやってみましょう。
class B def foo self.bar = 1 end private def bar=(arg) puts "bar= is private method" end end B.new.foo # => "bar= is private method"
この通りエラーが起きません。
privateメソッドがセッターメソッドの場合には、
明示的にレシーバを書いてもよいのです。
というよりも、明示的にレシーバを書かないとおかしなことになるからです。
以下にそれを示します。
class C def foo bar = 1 # ただのローカル変数の代入と見なされる end private def bar=(arg) puts "bar= is private method" end end C.new.foo # => 当然何も起こらない
セッターメソッドには明示的なレシーバが必要。
また、それはメソッドがprivateでもpublicでも変わることはありません。
この、privateメソッドのルールの例外については、
Twitterで @n0kada さんに教えていただきました。ありがとうございました。
http://twitter.com/n0kada/status/11625643920
セッターの件を Stuff To Be Considered in the Next Edition
返信削除http://pragprog.com/titles/ppmetr/errata
に入れてもらいましたので、増刷があれば修正されるはずです。
わわ、コメントありがとうございます!
返信削除そうですか、次刷では修正されるのですね。
メタプログラミングRuby、ほんとに良い本なので、
もっとたくさん売れるよう願っております!