144

この記事を読む前は、Ruby のアクセス制御は次のように機能すると思っていました。

  • public- 任意のオブジェクトからアクセスできます (例: Obj.new.public_method)
  • protected- オブジェクト自体およびサブクラス内からのみアクセス可能
  • private- protected と同じですが、メソッドはサブクラスに存在しません

ただし、明示的なレシーバーを使用してメソッドを呼び出すことができない (つまり、機能するが機能しない)という事実を除いて、 と は同じように動作するようですprotectedprivateprivateself.protected_methodself.private_method

これのポイントは何ですか?明示的なレシーバーでメソッドを呼び出したくないシナリオはいつですか?

4

8 に答える 8

171

protectedメソッドは、定義クラスまたはそのサブクラスの任意のインスタンスから呼び出すことができます。

privateメソッドは、呼び出し元のオブジェクト内からのみ呼び出すことができます。別のインスタンスのプライベート メソッドに直接アクセスすることはできません。

ここに簡単な実用的な例があります:

def compare_to(x)
 self.some_method <=> x.some_method
end

some_methodここにいることはできませんprivateprotected明示的な受信者をサポートするために必要だからです。典型的な内部ヘルパー メソッドは、privateこのように呼び出す必要がないため、通常はそうすることができます。

これは Java や C++ の動作とは異なることに注意してください。privateRubyprotectedでは、サブクラスがメソッドにアクセスできるという点で Java/C++ と似ています。privateRuby では、Javaのようにサブクラスからメソッドへのアクセスを制限する方法はありません。

いずれにせよ、Ruby での可視性は主に「推奨事項」ですsend

irb(main):001:0> class A
irb(main):002:1>   private
irb(main):003:1>   def not_so_private_method
irb(main):004:2>     puts "Hello World"
irb(main):005:2>   end
irb(main):006:1> end
=> nil

irb(main):007:0> foo = A.new
=> #<A:0x31688f>

irb(main):009:0> foo.send :not_so_private_method
Hello World
=> nil
于 2010-08-20T20:20:32.187 に答える
79

違い

  • 誰でもパブリックメソッドを呼び出すことができます。
  • 保護されたメソッドを呼び出すことも、クラスの別のメンバー(または子孫クラス)が外部から保護されたメソッドを呼び出すこともできます。他の誰もできません。
  • プライベートメソッドは暗黙のレシーバーでのみ呼び出すことができるため、プライベートメソッドを呼び出すことができるのはあなただけですselfあなたも呼び出すことはできませんself.some_private_method; 暗黙のうち private_methodに呼び出す必要があります。self
    • iGELは次のように指摘しています。「ただし、例外が1つあります。プライベートメソッドage =がある場合は、それをselfで呼び出して、ローカル変数から分離することができます(そしてそうしなければなりません)。」
    • Ruby 2.7以降、selfレシーバーは明示的にすることができますが、self.some_private_method許可されています。(ランタイム値がと同じであっても、他の明示的なレシーバーは引き続き許可されませんself。)

Rubyでは、これらの違いは、あるプログラマーから別のプログラマーへの単なるアドバイスです。非公開の方法は、「私はこれを変更する権利を留保します。それに依存しないでください」という言い方です。しかし、あなたはまだ鋭いはさみを手に入れ、sendあなたが好きな方法を呼び出すことができます。

簡単なチュートリアル

# dwarf.rb
class Dwarf
  include Comparable

  def initialize(name, age, beard_strength)
    @name           = name
    @age            = age
    @beard_strength = beard_strength
  end

  attr_reader :name, :age, :beard_strength
  public    :name
  private   :age
  protected :beard_strength

  # Comparable module will use this comparison method for >, <, ==, etc.
  def <=>(other_dwarf)
    # One dwarf is allowed to call this method on another
    beard_strength <=> other_dwarf.beard_strength
  end

  def greet
    "Lo, I am #{name}, and have mined these #{age} years.\
       My beard is #{beard_strength} strong!"
  end

  def blurt
    # Not allowed to do this: private methods can't have an explicit receiver
    "My age is #{self.age}!"
  end
end

require 'irb'; IRB.start

次に、ruby dwarf.rbこれを実行して実行できます。

gloin = Dwarf.new('Gloin', 253, 7)
gimli = Dwarf.new('Gimli', 62,  9)

gloin > gimli         # false
gimli > gloin         # true

gimli.name            # 'Gimli'
gimli.age             # NoMethodError: private method `age'
                         called for #<Dwarf:0x007ff552140128>

gimli.beard_strength # NoMethodError: protected method `beard_strength'
                        called for #<Dwarf:0x007ff552140128>

gimli.greet          # "Lo, I am Gimli, and have mined these 62 years.\
                           My beard is 9 strong!"

gimli.blurt          # private method `age' called for #<Dwarf:0x007ff552140128>
于 2013-03-18T14:39:52.157 に答える
7

Java のプライベート メソッドを考えてみましょう。もちろん、同じクラス内から呼び出すこともできますが、同じクラスの別のインスタンスから呼び出すこともできます。

public class Foo {

   private void myPrivateMethod() {
     //stuff
   }

   private void anotherMethod() {
       myPrivateMethod(); //calls on self, no explicit receiver
       Foo foo = new Foo();
       foo.myPrivateMethod(); //this works
   }
}

したがって、呼び出し元が同じクラスの別のインスタンスである場合、実際には、いわば「外部」からプライベート メソッドにアクセスできます。これにより、実際にはそれほどプライベートではないように見えます。

一方、Ruby では、プライベート メソッドは実際には現在のインスタンスに対してのみプライベートであることを意図しています。これは、明示的なレシーバーのオプションを削除すると提供されるものです。

一方で、Ruby コミュニティではこれらの可視性コントロールをまったく使用しないことが非常に一般的であることを指摘しておく必要があります。Java の世界とは異なり、すべてをアクセス可能にし、他の開発者が物事を台無しにしないことを信頼する傾向があります。

于 2010-08-20T20:27:23.943 に答える
4

Ruby でサブクラスからプライベート メソッドにアクセスできる理由の 1 つは、Ruby のクラスによる継承が、モジュール インクルードに対する薄いシュガー コーティングであるためです。実際、Ruby では、クラスは、継承などを提供する一種のモジュールです。

http://ruby-doc.org/core-2.0.0/Class.html

これが意味することは、基本的にサブクラスは親クラスを「含む」ため、プライベート関数を含む親クラスの関数がサブクラスでも効果的に定義されるということです。

他のプログラミング言語では、メソッドを呼び出すには、メソッド名を親クラス階層にバブリングし、メソッドに応答する最初の親クラスを見つける必要があります。対照的に、Ruby では、親クラスの階層はまだ存在しますが、親クラスのメソッドは、サブクラスが定義したメソッドのリストに直接含まれます。

于 2015-02-21T01:27:12.970 に答える
3

Java と Ruby のアクセス制御の比較: Java でメソッドが private と宣言されている場合、同じクラス内の他のメソッドからのみアクセスできます。メソッドが保護されていると宣言されている場合、同じパッケージ内に存在する他のクラスだけでなく、別のパッケージ内のクラスのサブクラスからもアクセスできます。メソッドが public の場合、誰でも見ることができます。Java では、アクセス制御の可視性の概念は、これらのクラスが継承/パッケージ階層のどこにあるかによって異なります。

一方、Ruby では、継承階層またはパッケージ/モジュールが適合しません。どのオブジェクトがメソッドのレシーバーであるかがすべてです。

Ruby のプライベート メソッドの場合、明示的なレシーバーで呼び出すことはできません。暗黙的なレシーバーを使用してプライベートメソッドを呼び出すことができます (のみ)。

これは、宣言されているクラス内およびこのクラスのすべてのサブクラス内からプライベート メソッドを呼び出すことができることも意味します。

class Test1
  def main_method
    method_private
  end

  private
  def method_private
    puts "Inside methodPrivate for #{self.class}"
  end
end

class Test2 < Test1
  def main_method
    method_private
  end
end

Test1.new.main_method
Test2.new.main_method

Inside methodPrivate for Test1
Inside methodPrivate for Test2

class Test3 < Test1
  def main_method
    self.method_private #We were trying to call a private method with an explicit receiver and if called in the same class with self would fail.
  end
end

Test1.new.main_method
This will throw NoMethodError

プライベート メソッドは、それが定義されたクラス階層の外から呼び出すことはできません。

保護されたメソッドは、private のように、暗黙的なレシーバーで呼び出すことができます。さらに、レシーバーが「自己」または「同じクラスのオブジェクト」である場合、明示的なレシーバー (のみ) によって保護されたメソッドを呼び出すこともできます。

 class Test1
  def main_method
    method_protected
  end

  protected
  def method_protected
    puts "InSide method_protected for #{self.class}"
  end
end

class Test2 < Test1
  def main_method
    method_protected # called by implicit receiver
  end
end

class Test3 < Test1
  def main_method
    self.method_protected # called by explicit receiver "an object of the same class"
  end
end


InSide method_protected for Test1
InSide method_protected for Test2
InSide method_protected for Test3


class Test4 < Test1
  def main_method
    Test2.new.method_protected # "Test2.new is the same type of object as self"
  end
end

Test4.new.main_method

class Test5
  def main_method
    Test2.new.method_protected
  end
end

Test5.new.main_method
This would fail as object Test5 is not subclass of Test1
Consider Public methods with maximum visibility

概要

パブリック: パブリック メソッドには最大の可視性があります

Protected: Protected メソッドは、private のように、暗黙の受信側で呼び出すことができます。さらに、レシーバーが「自己」または「同じクラスのオブジェクト」である場合、明示的なレシーバー (のみ) によって保護されたメソッドを呼び出すこともできます。

プライベート: Ruby のプライベート メソッドの場合、明示的なレシーバーで呼び出すことはできません。暗黙的なレシーバーを使用してプライベートメソッドを呼び出すことができます (のみ)。これは、宣言されているクラス内およびこのクラスのすべてのサブクラス内からプライベート メソッドを呼び出すことができることも意味します。

于 2017-07-18T03:50:49.267 に答える
3

違いは何ですか?

プライベート メソッドの説明

@freddie = Person.new
@freddie.hows_it_going?
# => "oh dear, i'm in great pain!"

class Person   
    # public method
    def hows_it_going?
        how_are_your_underpants_feeling?
    end

    private

    def how_are_your_underpants_feeling? # private method
        puts "oh dear, i'm in great pain!"
    end
end

パブリック メソッドであることを考えると、フレディに状況を尋ねることができます。それは完全に有効です。そして、それは正常であり、受け入れられます。

でも……フレディのパンツ事情を知っているのは、フレディ本人だけ。ランダムな見知らぬ人がフレディのパンツに手を伸ばして状況をテストすることはできません-いいえ、いいえ-それは非常に非常にプライベートであり、プライベートなものを外の世界に公開したくありません.

@freddie.how_are_your_underpants_feeling?
# => # NoMethodError: private method `how_are_your_underpants_feeling?' called

保護されたメソッドの説明

このことを考慮:

class Person
    
    protected

    def gimme_your_credit_card! # protected method
        puts "Fine. Whatever. Here it is: 1234-4567-8910"
    end
end

class Rib < Person
end

class Wife < Rib # wife inherits from Rib
    def i_am_buying_another_handbag_with_your_card(husband)        
        husband.gimme_your_credit_card!
    end
end

@husband = Person.new
@mrs = Wife.new
@mrs.i_am_buying_another_handbag_with_your_card(@husband)
# => puts "Fine. Whatever. Here it is: 1234-4567-8910"

mrsPerson から継承された生身の肉であることを考えると、クレジット カードの詳細を取得することには多少mrs問題はありませんが、ランダムな個人がクレジット カードの詳細にアクセスすることは望ましくありません。

サブクラスの外でそれを行おうとすると、失敗します。

@mrs = Wife.new
@mrs.gimme_your_credit_card!
# => protected method gimme_your_credit_card! called for #<Wife:0x00005567b5865818> (NoMethodError)

概要

  • プライベート メソッドは、「明示的な受信者」なしで、内部からのみ呼び出すことができます。(厳密に言えば、少しの Ruby マジックを使用してプライベート メソッドにアクセスできますが、ここではそれを無視します)。
  • 保護されたメソッドは、サブクラス内で呼び出すことができます。
  • 例/類推を使用して、鮮明に思い出せるようにしました。
于 2021-02-02T23:10:39.577 に答える