Go to list of users who liked
Share on X(Twitter)
Share on Facebook
More than 5 years have passed since last update.
概要
Ruby の private と protected の歴史と使い分けについて説明します。
いろんなところで断片的に書かれていることなのですが、有益な情報を
一箇所に集めると自分の理解が深まりそう=>他の人にも役立つかな?
と思ったのでまとめてみました。
具体的には、伊藤淳一さんのブログ・るりま・Rubyメーリングリストの内容を
一箇所にまとめた上で、私が書いたサンプルコードを少し足した内容になっています。
ちなみに Java や C# 畑の人が Ruby の private / protected を使って驚いた、
的な情報が多いですが、私も例にもれず Java => Ruby 勢で驚いたパターンです。
Java の private と protected
- public => どこからでもアクセス可能
- protected => クラス内、同一パッケージ、サブクラスからアクセス可
- private => クラス内のみアクセス可能
制限無く公開したいなら public 。
基本的に外部からは隠蔽するが、サブクラスやパッケージ内からのみ利用させたい場合は protected 。
基本的に外部からは隠蔽し、クラス内からのみ利用させたい場合は private 。
という使い分けになっていて、かなり分かりやすく、使い分ける目的も明確です。
今回の話には関係ありませんが、アクセス修飾子を省略した場合には default というスコープもあります。
- default => クラス内、同一パッケージからアクセス可
Ruby の private と protected
るりまを確認
るりまでは下記のように説明されています。
http://docs.ruby-lang.org/ja/2.1.0/doc/spec=2fdef.html#limit
- public => public に設定されたメソッドは制限なしに呼び出せます。
- protected => protected に設定されたメソッドは、そのメソッドを持つオブジェクトが self であるコンテキスト(メソッド定義式や instance_eval )でのみ呼び出せ ます。
- private => private に設定されたメソッドは関数形式でしか呼び出せません。
※便宜上、るりまとは表記順を変えてあります。(スコープの範囲が広い順にした方が分かりやすいと思ったので)
説明だけだとピンと来ないかもしれないので、サンプルコードを提示します。
private と protected の動作を確認
require'english'classScopeResearchClassdefpublic_method'public'enddefuse_protected(other)putsother.protected_methodenddefuse_private(other)other.private_methodrescueputs$ERROR_INFOenddefinternal_use_private_and_protectedputsprotected_methodputsprivate_methodenddefinternal_use_private_and_protected_with_recieverputsself.protected_methodself.private_methodrescueputs$ERROR_INFOendprotecteddefprotected_method'protected'endprivatedefprivate_method'private'endendpc1=ScopeResearchClass.newpc2=ScopeResearchClass.newbeginpc1.protected_methodrescue# protected は外部からは呼び出せずにエラーputs$ERROR_INFOendbeginpc1.private_methodrescue# private は外部からは呼び出せずにエラーputs$ERROR_INFOend# private / protected ともに内部から利用可能pc1.internal_use_private_and_protected# protected は レシーバーつきでも呼び出し可能# private は レシーバーつきだと呼び出せずpc1.internal_use_private_and_protected_with_recieverclassHogedefcan_not_use_external_protected_method(other)other.protected_methodrescueputs$ERROR_INFOendend# 関係ないクラス内からは呼び出せないことを確認Hoge.new.can_not_use_external_protected_method(pc2)# protected メソッドは自クラスに別インスタンスを渡しても呼び出し可能pc1.use_protected(pc2)# private メソッドは自クラスに別インスタンスを渡した場合、レシーバーの指定が出来ないのでエラーになるpc1.use_private(pc2)classChildProtectedClass<ScopeResearchClassdefuse_protected_from_child(other)putsother.protected_methodendend# protected メソッドはサブクラスに別インスタンスを渡しても呼び出し可能ChildProtectedClass.new.use_protected_from_child(pc2)- 出力
protected method `protected_method' called for #<ScopeResearchClass:0x0000060044c770>private method `private_method' called for #<ScopeResearchClass:0x0000060044c770>protectedprivateprotectedprivate method `private_method' called for #<ScopeResearchClass:0x0000060044c770>protected method `protected_method' called for #<ScopeResearchClass:0x0000060044c748>protectedprivate method `private_method' called for #<ScopeResearchClass:0x0000060044c748>protectedprotected を使うべき状況
protected を使うべき状況について、るりまにサンプルコードが掲載されていますが、
サンプルコードに少し補足をして、実行して動きを確認できるプログラムにしてみます。
classFoodef_val@valendprotected:_valdefop(other)# other も Foo のインスタンスを想定# _val が private だと関数形式でしか呼べないため# このように利用できないself._val+other._valendendf1=Foo.newf1.instance_variable_set(:@val,1)# => @val に無理やり 1 を設定f2=Foo.newf2.instance_variable_set(:@val,2)# => @val に無理やり 2 を設定putsf1.op(f2)# => 3Ruby の private と protected の歴史
伊藤淳一さんの素晴らしいブログエントリに Ruby のパパ「 Matz 」さんとのやりとりが
まとまっています。
http://blog.jnito.com/entry/20120315/1331754912
- Matz さん曰く
Rubyのprivateの発想の元になったのはSmalltalkの「privateカテゴリ」です。使わないでね、というだけでアクセスできちゃう。Rubyはそれよりは若干強制力があります。Rubyの反C++・親Smalltalkの設計思想が垣間見えますね後でprotectedを追加したのもまずかった。これでC++とキーワードが同じでも意味がズレてることになってしまったので。private と protected の使い分けに関する Matz さんの分かりやすい説明
Rubyのメーリングリストのやりとりより。
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/7669
- Matz さん曰く
つまり,privateは自分からしか見えないメソッドであるのに対して,protectedは一般の人からは見られたくないが,仲間(クラスが同じオブジェクト)からは見えるメソッドです.protectedは例えば2項演算子の実装にもう一方のオブジェクトの状態を知る必要があるか調べる必要があるが,そのメソッドをpublicにして,広く公開するのは避けたいというような時に使います.Ruby のメソッドの公開範囲の決定に関するマトリクス
| スコープ | 全体に公開したい | 外部から隠蔽したい | レシーバーを仲間が利用する |
|---|---|---|---|
| public | ○ | × | ○ |
| protected | × | ○ | ○ |
| private | × | ○ | × |
※仲間=自クラスかサブクラスのレシーバー
参照
るりまの クラス/メソッドの定義・呼び出し制限 の説明
http://docs.ruby-lang.org/ja/2.1.0/doc/spec=2fdef.html#limit伊藤淳一さんのブログより
JavaやC#の常識が通用しないRubyのprivateメソッド
http://blog.jnito.com/entry/20120315/1331754912Rubyのクラスメソッドは同じクラスのprotectedメソッドやprivateメソッドにアクセスできない
http://blog.jnito.com/entry/20120504/1336080083
Ruby のメーリングリストのやりとりより
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/7669るりまの Module クラスの public / protected / private の説明
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme