ruby中的Private vs Protected方法

如果方法受到保护,则可以由定义类或其子类的任何实例调用它。 如果方法是私有的,则只能在调用对象的上下文中调用它 – 它永远不可能直接访问另一个对象的私有方法,即使该对象与调用者属于同一个类。

当我在ruby中搜索private和protected方法之间的区别时,我从net获得了这个定义。

我对此有两个疑问

class Abc def abc xyz end protected def xyz p "hai" end end a=Abc.new a.abc 

在这个我隐含地在对象a上调用xyz,这就是我将如何调用xyz,即使它是私有的。所以“它可能被定义类的任何实例调用”这是什么意思?????

其次,

  class Abc def abc(obj) obj.xyz1 obj.xyz2 obj.xyz3 end end class Xyz def xyz1 p "called" end private def xyz2 p "called" end protected def xyz3 p "called" end end a=Abc.new b=Xyz.new a.abc(b) 

在这里,我可以在对象a上调用obj b的xyz1方法。但我无法在对象a上调用obj b的受保护xyz3和私有方法xyz2方法。“即使对象是直接访问另一个对象的私有方法也是不可能的。和来电者一样的class级。“ 这究竟是什么意思???

任何人都可以用更好的例子来帮助我理解这一个????

私人方法

要定义私有方法,我们使用private关键字,它实际上是在名为Module的类中实现的内置方法。 私有方法只能由定义它的类(或其子类之一)中的另一个方法调用。

 class Koan def call_say_koan say_koan end private def say_koan puts "What is the sound of one hand clapping?" end end k = Koan.new k.say_koan # Output: NoMethodError: private method `say_koan' called for # k.call_say_koan # Output: What is the sound of one hand clapping? 

在上面的例子中,我们不能直接调用say_koan私有方法(从类外部),但我们可以调用call_say_koan公共方法,而后者又称为say_koan。

同样在上面的示例中,内置私有方法使用时没有参数。 因此,下面定义的所有方法都是私有的。

private方法也可以与先前定义的方法名称(作为符号传递)一起用作参数。

 class Foo def some_method end private :some_method end 

为了使类方法成为私有,请使用private_class_method关键字/方法而不是私有。

不能使用接收器调用私有方法,例如self。 尝试在call_say_koan中使用self作为接收者(self.say_koan)调用say_koan方法将导致以下exception:

 NoMethodError: private method `say_koan' called for # 

从Ruby 2.0开始,respond_to? 当私有方法作为参数时,方法将返回false。

 k.respond_to? :say_koan # Output: => false 

要列出类中的所有私有实例方法,请使用private_instance_methods内置方法。 对于私有类方法,请使用private_methods。

 Koan.private_instance_methods(false) # Output => [:say_koan] 

受保护的方法

要定义受保护的方法,我们使用protected关键字(实际上是一个方法)。 与私有方法一样,受保护的方法也可以由定义它的类(或其子类之一)中的其他方法调用。 不同的是,受保护的方法也可以在同一个类的其他实例中调用。

没有受保护的类方法,Ruby只支持受保护的实例方法。

我们假设我们需要选择一些冥想者来参与一项研究。 为了找到最有经验的冥想者,我们需要比较他们的冥想总时数。 但是,我们不希望看到小时数。

 class Meditator def initialize(hours) @hours = hours end def more_experienced?(other_person) hours > other_person.hours end protected attr_reader :hours # We have made the accessor protected end m1 = Meditator.new 3000 m2 = Meditator.new 5000 m2.more_experienced? m1 # Output: => true m1.more_experienced? m2 # Output: => false 

虽然受保护的方法在Ruby中不常用,但类似的代码可用于保护任何类型的敏感数据免受外部访问(类及其实例之外)的影响。

当没有参数调用时(如上例所示),受保护的方法将其下面定义的所有方法转换为受保护的方法。 它还可用于保护先前定义的方法,如以下示例所示。

 class Foo def some_method end protected :some_method end 

要列出类中的所有受保护实例方法,请使用protected_instance_methods内置方法。 对于受保护的类方法,请使用protected_methods。

 Meditator.protected_instance_methods(false) # Output: => [:hours] 

考虑受保护和私有方法的最佳方式是它们如何影响您是否可以在方法调用之前明确指定接收方,即将其视为技术规则,而不是某种元思想。

  1. private方法 :您无法在私有方法调用之前显式指定接收方。 永远 (见评论)。 因为ruby总是使用某个接收器调用方法,所以ruby使用当前分配给self变量的任何对象作为接收器。

  2. protected method :在某些情况下,您可以为受保护的方法调用显式指定接收器。

然后,只需要探索ruby何时允许您在受保护的方法调用前明确指定接收器:

 class Dog def execute_pro(dog) dog.pro_meth end protected def pro_meth puts 'protected' end end d1 = Dog.new p d1.protected_methods d1.pro_meth --output:-- [:pro_meth] 1.rb:15:in `
': protected method `pro_meth' called for # (NoMethodError)

上面的例子certificate了这句话:

如果方法受到保护,则可以由定义类或其子类的任何实例调用它。

太笼统了。 但:

 class Dog def execute_pro(dog) dog.pro_meth end protected def pro_meth puts 'protected' end end d1 = Dog.new d2 = Dog.new p d1.protected_methods d1.execute_pro d2 --output:-- [:pro_meth] protected 

永远不可能直接访问另一个对象的私有方法,即使该对象与调用者属于同一个类。

在上面的示例中, 调用者是d1,并且 d1 调用 的方法内部 ,您可以直接访问d2的受保护方法,即您可以在受保护的方法调用之前显式指定接收器,因为d2与D1。 您将无法直接访问d2的私有方法 – 因为您永远无法在私有方法调用之前明确指定接收方。 这可能会让你相信……“好吧,私有和受保护是一回事:如果方法是私有的,我只需要删除显式接收器:

 class Dog def execute_pro(dog) pro_meth #<*****CHANGE HERE end private #<****CHANGE HERE def pro_meth puts 'protected' end end d1 = Dog.new d2 = Dog.new d1.execute_pro d2 --output:-- protected 

输出是相同的...但结论,“私有和受保护是相同的事情:如果方法是私有的,我只需要删除显式接收器。” 是错的。 这个例子太简单了,它掩盖了私有和受保护之间的细微差别。 这是一个更好的例子:

 class Dog1 def initialize(num) @num = num end def execute_pro(dog) dog.pro_meth end protected def pro_meth puts "protected -> #{@num}" end end d1 = Dog1.new 1 d2 = Dog1.new 2 d1.execute_pro d2 class Dog2 def initialize(num) @num = num end def execute_pro(dog) pro_meth #<****CHANGE HERE end private #<******CHANGE HERE def pro_meth puts "protected -> #{@num}" end end d1 = Dog2.new 1 d2 = Dog2.new 2 d1.execute_pro d2 --output:-- protected -> 2 protected -> 1 

输出显示您不能只将受保护的方法转换为私有方法,并从方法调用中删除显式接收器,并始终获得相同的结果。 在这种情况下,ruby允许您在受保护的方法调用之前显式指定接收器,以便让您将方法调用定向到正确的对象。 但受保护的方法与公共方法不同:

 class Dog def execute_pro(dog) dog.pro_meth end protected def pro_meth puts 'protected' end end class Poodle < Dog def dostuff(dog) dog.pro_meth end end class Cat def dostuff(dog) dog.pro_meth end end d1 = Dog.new p1 = Poodle.new c1 = Cat.new p1.dostuff d1 c1.dostuff d1 --output:-- protected 1.rb:21:in `dostuff': protected method `pro_meth' called for # (NoMethodError) from 1.rb:30:in `
'

在行c1.dostuff d1 ,调用者是c1,而在c1调用的内部方法中,你不能调用Dog的受保护方法 - 因为Cat类不是Dog类的同一个类或子类。 另请注意,如果您尝试删除显式接收器:

 class Cat def dostuff(dog) pro_meth #<****CHANGE HERE end end 

也不会调用Dog的受保护方法,因为在dostuff()内部,ruby将调用者分配给自变量,调用者是c1,所以你得到:

 class Cat def dostuff(dog) #self = c1 pro_meth end end ... c1.dostuff d1 

和ruby将方法调用pro_meth转换为self.pro_meth ,这相当于c1.pro_meth ,而Cat类没有定义名为pro_meth的方法。

你在某处选择的例子真的很混乱(特别是名字是abc或xyz,上下文很少)。 请允许我使用其他示例。

理论是这样的:

– 私人和受保护都可以通过公共方法从课外访问。

Protected和Private之间的区别是:

– 无法使用接收器调用私有方法(甚至不能使用#self)。 除非……调用私有的setter方法。 如果您尝试删除接收器,Ruby将创建一个局部变量。 在这种情况下,自我是必须的。

– 受保护可能会也可能不会使用#self等接收器。

– 受保护的可以访问来自同一类的另一个对象的受保护方法,私有不能。 (参见#eat_more_than(其他)方法的代码)

现在谈到inheritance……

– 私有方法只能在子类上隐式调用(只是方法的名称),而不是显式调用(使用#self)。

– 受保护可以双向调用(有或没有#self ||隐式或显式)。

我们来看看下面的例子:

  class Dog attr_accessor :name, :age def initialize(n, a) self.name = n self.age = a end def accessing_private "#{self.name} in human years is #{human_years}. This is secret!" end def accessing_protected "Will this work? " + a_protected_method end def eat_more_than(other) # accessing other instance's protected method from the same class daily_diet < other.daily_diet "#{name} eats more than #{other.name}" end def boy gender_method("boy") # accessing private setter method end protected def daily_diet age * 2 # the younger, the more they have to eat end def a_protected_method "Yes, I'm protected!" end private attr_writer :gender def gender_method(gender) self.gender = gender # private setter method requires self "#{name} is a #{gender}" end def human_years age * 8 end end # Create the first object of Dog blake = Dog.new("Blake", 5) p blake.accessing_private # "Blake in human years is 16. This is secret!" p blake.accessing_protected # "Will this work? Yes, I'm protected!" # Create the second object of Dog jackson = Dog.new("Jackson", 1) # Below, protected methods from different objects of the same type/class # are proven to share access p jackson.eat_more_than(blake) # true -> "Jackson eats more than Blake" # Below, accessing private setter method through a public method. p blake.boy # Blake is a boy 

现在在一个子类上,你不能用接收器调用一个inheritance的私有方法,但是受保护的方式会很好(有或没有接收器):

 class Puppy < Dog def accessing_protected_explicitly "Explicitly calls '#{self.a_protected_method}'" end def accessing_protected_implicitly "Implicitly calls '#{a_protected_method}'" end def accessing_private_implicitly "#{self.name} is #{human_years} years old in human years. This is a secret!" # implicit end def accessing_private_explicitly "#{self.name} is #{self.human_years} years old in human years" # explicit -> error end end # Below, testing them on a subclass booboo = Puppy.new("Booboo", 1 ) p booboo.accessing_protected_explicitly # works p booboo.accessing_protected_implicitly # works p booboo.accessing_private_implicitly # works p booboo.accessing_private_explicitly # error, called on a receiver 

我希望有所帮助!