ruby访问修饰符,不同版本2.5-2.7的不同输出
我正在尝试运行这段代码,它使用不同版本的ruby 2.5-2.7提供了不同的输出 代码:ruby访问修饰符,不同版本2.5-2.7的不同输出,ruby,access-modifiers,Ruby,Access Modifiers,我正在尝试运行这段代码,它使用不同版本的ruby 2.5-2.7提供了不同的输出 代码: class ParentClass def the_public_method self.method1 end private def method1 puts "The private has been called" end end class ChildClass < ParentClass
class ParentClass
def the_public_method
self.method1
end
private
def method1
puts "The private has been called"
end
end
class ChildClass < ParentClass
def test
self.method1
end
end
ParentClass.new.the_public_method
ChildClass.new.test
Traceback (most recent call last):
1: from main.rb:19:in `<main>'
main.rb:3:in `the_public_method': private method `method1' called for
#<ParentClass:0x000056367ee0b388> (NoMethodError)
Did you mean? method
methods
exit status 1
The private has been called
The private has been called
我认为第一个输出对于旧版本的ruby是正确的。。
有什么反馈吗?
在Ruby 2.7之前,允许使用文本self作为接收方调用私有写/分配方法,但使用self调用任何其他私有方法都会抛出NoMethodError错误
Ruby 2.7旨在标准化self和private方法之间的交互。Ruby 2.7已经修复了上述不一致性
因此,Ruby 2.7之前的第一个输出是正确的,Ruby 2.7之后的第二个输出是正确的。在Ruby中,仍然可以从继承的类访问
private
方法,但用于要求非显式接收(即隐式调用,如mehtod1
但不obj.method1
或self.method1
)
正如@eux所说,最后一个要求已经放宽,所以现在您也可以调用self.method
Ruby中可见性的另一个怪癖是它链接到实例而不是类本身。这将解释
private
的行为,并让您了解以下代码:
class-Foo
def初始化(名称)
@name=name
结束
def==(右侧)
name==rhs.name
结束
私有的
属性读取器:名称
结束
f=食品新(“酒吧”)
f==f#命名错误
这里出现命名错误是因为attr\u reader:name
是私有的,因此您无法访问另一个对象的name
。要启用此行为,请使用protected
我认为第一个输出对于旧版本的ruby是正确的。。有什么反馈吗
两个输出都是正确的。规范在Ruby 2.7中进行了更改,因此Ruby 2.7的行为自然有所不同
最初,私有方法的规则是“只有在没有显式接收方的情况下才能调用私有方法”
但是,这意味着您不能使用私有setter,因为foo=:bar
是一个局部变量赋值,并且不允许使用self.foo=:bar
因此,规则被更改为“只能在没有显式接收器的情况下调用私有方法,但setter除外,setter允许文本伪变量self
作为接收器”
但是,这仍然不能解释像self+2
或self.foo+=2
这样的事情,其中++
、foo
或foo=
是私有的,还有许多其他的角落案例
有一段时间,Ruby开发人员试图解决这个问题,要么忽略其中一些极端情况,要么添加一组更加复杂的异常,但实际上,解决方案相当简单:将规则更改为“只能使用文本伪变量self
作为显式或隐式接收器调用私有方法”
这是Ruby 2.7以来的规则。不幸的是,角落案例
obj=self;obj.foo
仍然失败。所有这些定义的一个共同点是,它们可以进行语法检查。一些实现者(我个人知道JRuby和TruffleRuby)一直强烈希望保留这个属性,自从Ruby中存在私有方法以来,这个属性就一直存在。一直以来,只有文字伪变量self
可以用作私有方法的显式接收器。否则,您会遇到诸如def foo;如果rand<0.5,则self-else-Object.new-end;foo.bar
,现在如果bar
是私有的,那么这是允许的还是不允许的?是的,您必须在调用时进行检查。但我不明白为什么这是件坏事。