Ruby on rails 澄清Ruby中“私有”和“受保护”的定义?

Ruby on rails 澄清Ruby中“私有”和“受保护”的定义?,ruby-on-rails,ruby,access-specifier,Ruby On Rails,Ruby,Access Specifier,如果一个方法受到保护,它可以被定义该方法的任何实例调用 类或其子类。如果方法是私有的,则只能在 调用对象的上下文永远不可能访问另一个对象 对象的私有方法,即使该对象属于同一类 作为来电者 -编程Ruby、类、对象和变量: 当我在ruby中搜索私有方法和受保护方法之间的区别时,我从net获得了这个定义 我对此有两个疑问 class Abc def abc xyz end protected def xyz p "hai" end end a

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

-编程Ruby、类、对象和变量:

当我在ruby中搜索私有方法和受保护方法之间的区别时,我从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方法。因此,即使对象与调用方属于同一类,也永远不可能直接访问另一个对象的私有方法。这到底是什么意思


有谁能用更好的例子帮助我理解这一点吗???

思考受保护和私有方法的最佳方式是它们如何影响您是否可以在方法调用之前显式指定接收者,也就是说,将其视为技术规则,而不是某种元概念


私有方法:不能在私有方法调用之前显式指定接收方。Eversee评论。因为ruby总是使用某个接收者调用方法,所以ruby使用当前分配给self变量的任何对象作为接收者

受保护方法:在某些情况下,可以显式指定受保护方法调用的接收方

然后,只需探索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 `<main>': protected method `pro_meth' called for #<Dog:0x007f8ef90e0eb8> (NoMethodError)
永远不可能直接访问另一个对象的私有方法,即使该对象与调用方属于同一类

在上面的示例中,调用方是d1,在d1调用的方法中,您可以直接访问d2的受保护方法,也就是说,您可以在受保护的方法调用之前显式指定接收方,因为d2与d1属于同一类。您将无法直接访问d2的私有方法,因为您永远无法在私有方法调用之前显式指定接收方。这可能会让你相信…好吧,private和protected是一样的:如果方法是private,我只需要删除显式接收器:

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
这也不会调用Dog的protected方法,因为在dostuff内部,ruby将调用者分配给self变量,调用者是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的方法。

考虑受保护和私有方法的最佳方式是它们如何影响您是否可以在方法调用之前显式指定接收者,也就是说,将其视为一项技术规则,而不是某种元概念


私有方法:不能在私有方法调用之前显式指定接收方。Eversee评论。因为ruby总是使用某个接收者调用方法,所以ruby使用当前分配给self变量的任何对象作为接收者

受保护方法:在某些情况下,可以显式指定受保护方法调用的接收方

然后,只需探索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 `<main>': protected method `pro_meth' called for #<Dog:0x007f8ef90e0eb8> (NoMethodError)
永远不可能直接访问另一个对象的私有方法,即使该对象与调用方属于同一类

在上面的示例中,调用方是d1,在d1调用的方法中,您可以直接访问d2的受保护方法,也就是说,您可以在受保护的方法调用之前显式指定接收方,因为d2与d1属于同一类。您将无法直接访问d2的私有方法,因为您永远无法在私有方法调用之前显式指定接收方。这可能会让你相信…好吧,private和protected是一样的:如果方法是private,我只需要删除显式接收器:

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
这也不会调用Dog的protected方法,因为在dostuff内部,ruby将调用者分配给self变量,调用者是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的方法。

Private Methods 要定义私有方法,我们使用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 #<Koan:0x000000021e7380>
k.call_say_koan        # Output: What is the sound of one hand clapping?
为了使类方法p 使用private\u class\u method关键字/方法代替private

无法使用接收方(如self)调用私有方法。尝试调用self作为接收方self的say_koan方法。call_say_koan中的say_koan将导致以下异常:

NoMethodError: private method `say_koan' called for #<Koan:0x000000021eb548>
要列出类中的所有私有实例方法,请使用内置的private_instance_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
要列出类中所有受保护的实例方法,请使用内置的受保护的\u实例\u方法。对于受保护的类方法,请使用受保护的方法

Meditator.protected_instance_methods(false)  # Output: => [:hours]
私有方法 要定义私有方法,我们使用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 #<Koan:0x000000021e7380>
k.call_say_koan        # Output: What is the sound of one hand clapping?
要使类方法私有,请使用private\u class\u method关键字/method而不是private

无法使用接收方(如self)调用私有方法。尝试调用self作为接收方self的say_koan方法。call_say_koan中的say_koan将导致以下异常:

NoMethodError: private method `say_koan' called for #<Koan:0x000000021eb548>
要列出类中的所有私有实例方法,请使用内置的private_instance_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
要列出类中所有受保护的实例方法,请使用内置的受保护的\u实例\u方法。对于受保护的类方法,请使用受保护的方法

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

您在某处选择的示例确实令人困惑,尤其是名称abc或xyz,几乎没有上下文。请允许我举一个不同的例子

理论是这样的:

–私有和受保护都可以通过公共方法从类外部访问

受保护和私有的区别是:

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

–受保护的用户可以使用或不使用self等接收器

–Protected可以访问来自同一类的另一个对象的Protected方法,Private不能。有关方法eat\u more\u,请参见代码

现在说到遗产

–只能对子类隐式地调用私有方法,而不是显式地使用self

–Protected可以通过包含或不包含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 
现在,在一个子类上,您不能使用接收方调用继承的私有方法,但受保护的方法只能这样做 无论是带接收器还是不带接收器:

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

我希望这有帮助

您在某处选择的示例确实令人困惑,尤其是名称abc或xyz,几乎没有上下文。请允许我举一个不同的例子

理论是这样的:

–私有和受保护都可以通过公共方法从类外部访问

受保护和私有的区别是:

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

–受保护的用户可以使用或不使用self等接收器

–Protected可以访问来自同一类的另一个对象的Protected方法,Private不能。有关方法eat\u more\u,请参见代码

现在说到遗产

–只能对子类隐式地调用私有方法,而不是显式地使用self

–Protected可以通过包含或不包含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 
现在在一个子类上,您不能使用接收方调用继承的私有方法,但无论是否使用接收方,protected都可以:

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

我希望这有帮助

不能在私有方法调用之前显式指定接收方。曾经除非要调用私有setter,否则必须使用显式接收器,因为否则它将被解释为对局部变量的赋值。还有一个,我两年前申请的,我们希望有一天能看到。除非你想称一个私人二传手为好球。这些年来,我在好几个地方发布了关于这一例外的帖子。忘记了。您不能在私有方法调用之前显式指定接收者。曾经除非要调用私有setter,否则必须使用显式接收器,因为否则它将被解释为对局部变量的赋值。还有一个,我两年前申请的,我们希望有一天能看到。除非你想称一个私人二传手为好球。这些年来,我在好几个地方发布了关于这一例外的帖子。忘了吧。