“私人”是否有充分的理由像Ruby一样工作?

我花了一段时间才了解私有方法在Ruby中是如何工作的,这让我觉得非常尴尬。 有谁知道私人方法是否有充分的理由按照它们的方式处理? 这只是历史原因吗? 还是实施原因? 还是有很好的合理逻辑(即语义)?

例如:

class Person private attr_reader :weight end class Spy < Person private attr_accessor :code public def test code #(1) OK: you can call a private method in self Spy.new.code #(2) ERROR: cannot call a private method on any other object self.code #(3) ERROR!!! cannot call a private method explicitly on 'self' code="xyz" #(4) Ok, it runs, but it actually creates a local variable!!! self.code="z" #(5) OK! This is the only case where explicit 'self' is ok weight #(6) OK! You can call a private method defined in a base class end end 
  • Ruby在第(1),(2)和(5)行上的行为似乎是合理的。
  • (6)没问题的事实有点奇怪,特别是来自Java和C ++。 有什么好理由吗?
  • 我真的不明白为什么(3)失败了! 一个解释,有人吗?
  • 第(4)行的问题看起来像语法中的含糊不清,与“私人”无关。

有任何想法吗?

您可能会发现阅读ruby对public,private和protected的定义很有帮助。 (跳到访问控制)

Ruby的私有类似于Java的受保护。 没有Ruby相当于Java的私有。 编辑:这个解决方案现在提供了一种方法来伪造Java在Ruby对象中的私有理想。

Private被定义为只能隐式调用的方法/变量。 这就是语句2和3失败的原因。 换句话说,private将方法/变量限制为定义它们的类或子类的上下文。 inheritance将私有方法传递给子类,因此可以使用隐式self访问。 (解释为什么声明6有效。)

我认为你正在寻找更接近受保护的东西。 其行为类似于未提供可见性的Java访问器(例如:public,private,protected)通过将Spy中的private更改为受保护的所有6个语句都可以正常工作。 受保护的方法可以由定义类的任何实例或其子类调用。 只要调用者是响应调用的对象的类,或者从调用inheritance,对于受保护方法的显式或隐式调用都是有效的语句。

 class Person private attr_reader :weight end class Spy < Person protected attr_accessor :code public def test code #(1) OK: you can call a private method in self Spy.new.code #(2) OK: Calling protected method on another instance from same class family or a descendant. self.code #(3) OK: Calling protected method on with explicit self is allowed with protected code="xyz" #(4) Ok, it runs, but it actually creates a local variable!!! self.code="z" #(5) OK! This is the only case where explicit 'self' is ok weight #(6) OK! You can call a private method defined in a base class end end s = Spy.new s.test # succeeds s.code #(7) Error: Calling protected method outside of the class or its descendants. 

至于陈述4.你认为这是为了避免含糊不清是正确的。 它更能保护ruby动态性的潜在危害。 它确保您不能通过稍后再次打开该类来覆盖访问者。 可能出现的情况,例如通过评估受污染的代码。

我只能推测他导致这些行为的设计决策。 对于大多数人来说,我觉得这取决于语言的动态性。

PS如果你真的想给私人的java定义。 仅适用于定义它的类,甚至不适用于子类。 您可以向类中添加self.inherited方法,以删除对要限制访问的方法的引用。

使子类的权重属性不可访问:

 class Person private attr_reader :weight def initialize @weight = 5 end def self.inherited(subclass) subclass.send :undef_method, :weight end end class Spy < Person private attr_accessor :code public def test weight end end Person.new.send(:weight) # => 5 Spy.new.send(:weight) #=> Unhelpful undefined method error 

将undef_method调用替换为以下内容可能更有意义:

  def self.inherited(subclass) subclass.class_eval %{ def weight raise "Private method called from subclass. Access Denied" end } end 

这提供了更有用的错误和相同的function。

发送是必要的,以便为其他类调用私有方法。 仅用于certificate事情确实有效。

事后看来,使私人和受保护无用。 如果您真的非常认真地保护自己的方法,则必须重写发送以阻止它们。 以下代码基于对象的private_methods执行此操作:

 def send_that_blocks_private_methods(method, *args) if private_methods.include?(method.to_s) raise "Private method #{method} cannot called be called with send." else send_that_allows_private_methods(method, *args) end end alias_method :send_that_allows_private_methods, :send alias_method :send, :send_that_blocks_private_methods private :send_that_allows_private_methods 

您可以指定要阻止访问的private_methods的class_variable,而不是拒绝访问所有私有方法。 您也可以将send设为私有,但是从对象外部调用send是合法的用法。