为什么Ruby既有私有方法又有受保护方法?

r8xiu3jd  于 2023-01-12  发布在  Ruby
关注(0)|答案(8)|浏览(170)

在阅读this article之前,我认为Ruby中的访问控制是这样工作的:

  • public-可由任何对象访问(例如Obj.new.public_method
  • protected-只能从对象本身以及任何子类中访问
  • private-与protected相同,但子类中不存在该方法

然而,protectedprivate的行为似乎是一样的,除了你不能用显式接收器调用private方法(即self.protected_method工作,而self.private_method不工作)。
这有什么意义呢?什么时候会有这样的场景,你不希望你的方法被显式的接收者调用?

ev7lccsx

ev7lccsx1#

protected方法可以由定义类或其子类的任何示例调用。
只能从调用对象内部调用private方法。不能直接访问其他示例的私有方法。
下面是一个快速的实际示例:

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

some_method在这里不能是private。它必须是protected,因为您需要它来支持显式接收器。您的典型内部帮助器方法通常可以是private,因为它们从来不需要这样调用。
需要注意的是,这与Java或C的工作方式不同。Ruby中的private与Java/C中的protected类似,因为它们的子类可以访问方法。在Ruby中,无法像Java中的private那样限制从子类访问方法。
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
dxxyhpgq

dxxyhpgq2#

区别

  • 任何人都可以调用你的公共方法。
  • 你可以调用你的protected方法,或者你的类(或者子类)的另一个成员可以从外部调用你的protected方法,其他人都不能。
  • 只有你可以调用你的私有方法,因为它们只能用self的隐式接收方调用。即使你也不能调用self.some_private_method;你必须调用private_method并隐含self
  • iGEL指出:“不过有一个例外,如果你有一个私有方法age=,你可以(也必须)用self调用它,把它和局部变量分开。”
  • 自Ruby 2.7以来,self接收器可以是显式的,self.some_private_method是允许的(任何其他显式接收器仍然是不允许的,即使运行时值与self相同)。

在Ruby中,这些区别只是程序员之间的建议。**非公共方法是一种表达“我保留更改此方法的权利;don 't dependent it."**但是您仍然可以得到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>
vxqlmq5t

vxqlmq5t3#

Ruby中的私有方法:

如果一个方法在Ruby中是私有的,那么它不能被显式的接收者(对象)调用,只能被隐式调用,它可以被描述它的类以及该类的子类隐式调用。
下面的例子将更好地说明这一点:
1)具有私有方法class_name的Animal类

class Animal
  def intro_animal
    class_name
  end
  private
  def class_name
    "I am a #{self.class}"
  end
end

在这种情况下:

n = Animal.new
n.intro_animal #=>I am a Animal
n.class_name #=>error: private method `class_name' called

2)两栖类动物的一个亚纲:

class Amphibian < Animal
  def intro_amphibian
    class_name
  end 
end

在这种情况下:

n= Amphibian.new
  n.intro_amphibian #=>I am a Amphibian
  n.class_name #=>error: private method `class_name' called

正如你所看到的,私有方法只能被隐式调用,它们不能被显式的接收者调用,同样的原因,私有方法也不能在定义类的层次结构之外被调用。

Ruby中的受保护方法:

如果一个方法在Ruby中是受保护的,那么它可以被定义类和它的子类隐式调用。另外,它们也可以被显式接收者调用,只要接收者是self或者与self属于同一个类:
1)具有受保护方法protect_me的Animal类

class Animal
  def animal_call
    protect_me
  end
  protected
  def protect_me
    p "protect_me called from #{self.class}"
  end  
end

在这种情况下:

n= Animal.new
n.animal_call #=> protect_me called from Animal
n.protect_me #=>error: protected method `protect_me' called

2)从动物纲继承而来的哺乳动物纲

class Mammal < Animal
  def mammal_call
    protect_me
  end
end

在这种情况下

n= Mammal.new
n.mammal_call #=> protect_me called from Mammal

3)从动物纲继承而来的两栖纲(与哺乳纲相同)

class Amphibian < Animal
  def amphi_call
    Mammal.new.protect_me #Receiver same as self
    self.protect_me  #Receiver is self
  end   
end

在这种情况下

n= Amphibian.new
n.amphi_call #=> protect_me called from Mammal
             #=> protect_me called from Amphibian

4)一个叫Tree的类

class Tree
  def tree_call
    Mammal.new.protect_me #Receiver is not same as self
  end
end

在这种情况下:

n= Tree.new
n.tree_call #=>error: protected method `protect_me' called for #<Mammal:0x13410c0>
k4aesqcs

k4aesqcs4#

考虑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社区中,根本不使用这些可见性控件是很常见的,因为Ruby无论如何都会给你提供绕过这些控件的方法。与Java世界不同,现在的趋势是让所有东西都可以访问,并相信其他开发人员不会把事情搞砸。

camsedfj

camsedfj5#

□ □有什么区别?

解释私有方法

@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,事情进展如何,因为这是一个公开的方法,这是完全有效的,这是正常的,可以接受的。
但是......唯一能知道弗雷迪内裤情况的人,就是弗雷迪自己。随便一个陌生人把手伸进弗雷迪的内裤是不行的--不,不--这是非常非常隐私的,我们不想把隐私暴露给外界。换句话说,我们可能不想把可变数据暴露给世界上的任何调用者。有人可能会改变一个值,我们会在痛苦的世界里试图找出虫子的来源。

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

受保护方法说明

想想这个:

class Person    
    protected

    def hand_over_the_credit_card! # protected method
        puts "Lawd have mercy. 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.hand_over_the_credit_card! # equalityInAction    
    end
end

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

我们对mrs获取我们的信用卡详细信息有点满意,因为mrs是我们的血肉之躯,继承自Person,所以她可以在一些鞋子等上搞砸,但我们不希望随机的个人获取我们的信用卡详细信息。
如果我们试图在子类之外这样做,它将失败:

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

总结

  • 私有方法只能从内部调用,并且没有"显式接收器"(严格地说,您可以使用一点ruby魔术来访问私有方法,但我现在将忽略它)。
  • 受保护的方法可以在子类内调用。
  • 我用这些例子/类比来帮助你生动地记住。
huwehgph

huwehgph6#

在Ruby中,私有方法可以被子类访问的部分原因是Ruby对类的继承是对Module includes的一层薄薄的糖衣, -在Ruby中,类实际上是一种提供继承的模块,等等。
http://ruby-doc.org/core-2.0.0/Class.html
这意味着子类基本上“包含”父类,因此父类的函数(* 包括私有函数 *)也在子类中定义。
在其他编程语言中,调用一个方法需要将方法名向上冒泡到父类层次结构中,并找到响应该方法的第一个父类。相反,在Ruby中,当父类层次结构仍然存在时,父类的方法直接包含在子类定义的方法列表中。

1tu0hz3e

1tu0hz3e7#

**Java与Ruby的访问控制比较:**如果方法在Java中声明为private,则只能由同一个类中的其他方法访问。如果方法声明为protected,则可以由同一个包中的其他类以及不同包中该类的子类访问。当方法为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一样。此外,受保护的方法还可以由显式接收方调用(仅当接收方是“self”或“同一类的对象”时)。

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一样。此外,Protected方法也可以被显式接收方调用,(仅)当接收方是“self”或“同一类的对象”时。
Private:对于Ruby中的私有方法来说,它永远不能被显式接收器调用。我们只能用隐式接收器调用私有方法。这也意味着我们可以从声明私有方法的类以及该类的所有子类中调用私有方法。

yacmzcpb

yacmzcpb8#

前三种类型的访问说明符和定义其作用域的说明符。
1.公共-〉访问类之外的任何地方。
1.私有-〉不能访问类的外部。
1.保护-〉此方法不能访问此方法定义范围的任何地方。
但我有一个解决这个问题的所有方法如何访问深入解释。

class Test
  attr_reader :name

  def initialize(name)
    @name = name
  end
  
  def add_two(number)
    @number = number 
  end
  
  def view_address
    address("Anyaddress")
  end
  
  private 

  def address(add)
    @add = add
  end
  
  protected 

  def user_name(name)
    # p 'call method'
    @name = name
  end
end

class Result < Test
  def new_user
    user_name("test355")
  end
end

1.对象列表

  1. p测试= www.example.com("测试") Test.new ("test")
  2. p www.示例网站 test.name
  3. p检验.添加_二(3)
    1.列表项
  4. p测试.查看地址
  5. p r = www.example.com("") Result.new ("")
  6. p www.example.com_用户 r.new _user

相关问题