【问题标题】:Can method visibility be inherited in ruby?可以在 ruby​​ 中继承方法可见性吗?
【发布时间】:2014-09-11 00:37:13
【问题描述】:

考虑Ruby中的以下示例:

class ParentClass
  private def method
    puts "private method"
  end
end

class ChildClass < ParentClass
  def method
    puts "overridden, but should be private too"
  end
end

ParentClass.new.method #=> raises exception
ChildClass.new.method  #=> produces "overridden, but should be private too"

如果我无法控制ChildClass 的代码,是否可以让它从ParentClass 继承方法可见性?

【问题讨论】:

  • 问题:如果对ChildClass没有控制权,为什么需要保证方法是私有的?也许他们毕竟希望它公开?
  • 查找程序中的错误。我的意思是肯定有其他方法,但我很好奇它是否可能! ;)

标签: ruby inheritance methods


【解决方案1】:

您的问题与继承无关。这里相关的是类方法private 的时间安排。请参阅下面的简化示例。调用时,此方法会将此时存在的相关方法转换为私有方法。

class A
  def foo; "foo1" end
  private :foo
  new.foo # => NoMethodError: private method `foo' called for #<A:0x007f321204fec0>
end

当你在private 应用后更改方法时,会定义一个同名的新方法,而private 应用到之前定义的效果就没有了。

class A
  def foo; "foo2" end
  new.foo # => "foo2"
end

当你再次调用 private 时,它就会变成私有的:

class A
  private :foo
  new.foo # => NoMethodError: private method `foo' called for #<A:0x007f3211ff6de8>
end

使用您的原始示例来说明这一点...

class ChildClass 
  private :method
end

... 可以在 ChildClass 的初始定义之后完成,并将 method 方法设为私有。

总而言之,可见性是(定义的)方法的属性,而不是方法名称的属性。因此,您不能重新定义一个方法,但具有以前同名方法的私有状态,但您可以更改当前方法的私有状态。

【讨论】:

    【解决方案2】:

    所有对象,首先要优先于它们自己的定义的方法,即使它们的类也有同名的方法。但是,如果您真的想在某些情况下调用 parent 类方法,那么您可以从#class_eval 获取 help

    class ParentClass
      private
      def biz
        puts "private method"
      end
    end
    
    class ChildClass < ParentClass
      def biz
        puts "overridden, but should be private too"
      end
    end
    
    ChildClass.class_eval do
      remove_method :biz
      self.new.biz
    end
    # private method `biz' called for #<ChildClass:0x8c3532c> (NoMethodError)
    

    现在,看到ChildClass 对象正在从ParentClass 调用private 方法。现在要使调用成功,您需要使用#send

    ChildClass.class_eval do
      remove_method :biz
      self.new.send :biz # => private method
    end
    

    另一种方式,我在大多数情况下使用的是:-

    unbind = ParentClass.instance_method(:biz)
    unbind.bind(ChildClass.new).call # => private method
    

    真的,当您执行 inheritmixin 时,无论物理上不是什么方法都不会分别进入孩子或在课堂上混合。它们(父类或混合在模块中)实际上被添加到类ChildClassmethod lookup链中。

    【讨论】:

      猜你喜欢
      • 2018-11-20
      • 1970-01-01
      • 2012-10-14
      • 2014-04-14
      • 2020-01-22
      • 1970-01-01
      • 2011-04-16
      • 1970-01-01
      • 2011-03-04
      相关资源
      最近更新 更多