Min*_*ark 25 ruby language-design private access-specifier
我花了一段时间才了解私有方法在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
Run Code Online (Sandbox Code Playgroud)
有任何想法吗?
EmF*_*mFi 32
您可能会发现阅读ruby对public,private和protected的定义很有帮助.(跳到访问控制)
Ruby的私有类似于Java的受保护.没有Ruby相当于Java的私有.编辑:这个解决方案现在提供了一种方法来伪造Java在Ruby对象中的私有理想.
Private被定义为只能隐式调用的方法/变量.这就是语句2和3失败的原因.换句话说,private将方法/变量限制为定义它们的类或子类的上下文.继承将私有方法传递给子类,因此可以使用隐式self访问.(解释为什么声明6有效.)
我认为你正在寻找更接近受保护的东西.其行为类似于未获得可见性的Java访问器(例如:public,private,protected)通过将Spy中的private更改为受保护的所有6个语句都可以工作.受保护的方法可以由定义类的任何实例或其子类调用.只要调用者是响应调用的对象的类,或者从调用继承,对于受保护的方法显式或隐式调用都是有效的语句.
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.
Run Code Online (Sandbox Code Playgroud)
至于陈述4.你认为这是为了避免含糊不清是正确的.它更能保护红宝石动态性的潜在危害.它确保您不能通过稍后再次打开该类来覆盖访问者.可能出现的情况,例如通过评估受污染的代码.
我只能推测他导致这些行为的设计决策.对于大多数人来说,我觉得这取决于语言的动态性.
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
Run Code Online (Sandbox Code Playgroud)
将undef_method调用替换为以下内容可能更有意义:
def self.inherited(subclass)
subclass.class_eval %{
def weight
raise "Private method called from subclass. Access Denied"
end
}
end
Run Code Online (Sandbox Code Playgroud)
这提供了更有用的错误和相同的功能.
发送是必要的,以便为其他类调用私有方法.仅用于证明事情确实有效.
事后看来,使私人和受保护无用.如果您真的非常认真地保护自己的方法,则必须覆盖发送以阻止它们.以下代码基于对象的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
Run Code Online (Sandbox Code Playgroud)
您可以指定要阻止访问的private_methods的class_variable,而不是拒绝访问所有私有方法.您也可以将send设为私有,但是从对象外部调用send是合法的用法.
归档时间: |
|
查看次数: |
4145 次 |
最近记录: |