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

我正在尝试运行这段代码,它使用不同版本的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 
    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
是私有的,那么这是允许的还是不允许的?是的,您必须在调用时进行检查。但我不明白为什么这是件坏事。