ruby 访问修饰符,不同版本的不同输出 2.5 - 2.7

Posted

技术标签:

【中文标题】ruby 访问修饰符,不同版本的不同输出 2.5 - 2.7【英文标题】:ruby access modifiers, different output with different versions 2.5 - 2.7 【发布时间】:2021-06-18 20:25:09 【问题描述】:

我正在尝试运行此代码,它使用不同版本的 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

ruby 2.5 上提供:

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

ruby 2.7 上提供:

The private has been called
The private has been called

我认为旧版本的 ruby​​ 的第一个输出是正确的。 有任何反馈吗?

【问题讨论】:

【参考方案1】:

我认为旧版本的 ruby​​ 的第一个输出是正确的。有任何反馈吗?

两个输出都是正确的。 Ruby 2.7 中的规范发生了变化,因此 Ruby 2.7 的行为自然会有所不同。

最初,私有方法的规则是“私有方法只能在没有显式接收者的情况下调用”。

然而,这意味着你不能使用私有的setter,因为foo = :bar是一个局部变量赋值并且self.foo = :bar是不允许的。

因此,规则已更改为“只能在没有显式接收者的情况下调用私有方法,但 setter 除外,其中允许文字伪变量 self 作为接收者”。

但是,这仍然没有考虑到诸如 self + 2self.foo += 2 之类的事情,其中​​ +foofoo= 是私有的,以及许多其他极端情况。

有一段时间,Ruby 开发人员试图通过忽略一些极端情况或添加一组更复杂的异常来解决这个问题,但实际上,解决方案相当简单:将规则更改为“私有方法”只能用字面伪变量self 作为显式或隐式接收器调用。

这是自 Ruby 2.7 以来的规则。

【讨论】:

不幸的是,角落案例obj = self ; obj.foo 仍然失败。 所有这些定义都有一个共同点,那就是可以对它们进行语法检查。几个实现者(我个人知道 JRuby 和 TruffleRuby)强烈希望保留这个属性,自从 Ruby 中存在私有方法以来,这一直是事实。始终要求只有文字伪变量self 可以用作私有方法的显式接收器。否则,你会遇到像def foo; if rand &lt; 0.5 then self else Object.new end end; foo.bar 这样的问题,现在如果bar 是私有的,是否允许? 是的,您必须在调用时进行检查。但我不明白为什么这是一件坏事。【参考方案2】:

Ruby 2.7 allows calling a private method with self

在 Ruby 2.7 之前,允许使用字面量 self 作为接收者调用私有写入/赋值方法,但使用 self 调用任何其他私有方法会引发 NoMethodError 错误。

Ruby 2.7 旨在标准化 self 和 private 方法之间的交互。上述不一致已在 Ruby 2.7 中得到修复。

所以在 Ruby 2.7 之前第一个输出是正确的,在 Ruby 2.7 之后第二个输出是正确的。

【讨论】:

【参考方案3】:

在 Ruby 中,private 方法仍然可以从继承的类中访问,但过去需要非显式接收(即隐式调用,如 mehtod1 但不是 obj.method1self.method1

正如@eux 所说,最后一个要求已经放宽了in ruby 2.7,因此您现在也可以致电self.method


Ruby 中可见性的另一个怪癖是它链接到实例而不是类本身。这解释了private的行为,让你理解下面的代码:

class Foo
  def initialize(name)
    @name = name
  end

  def ==(rhs)
    name == rhs.name
  end

  private

  attr_reader :name
end

f = Foo.new("bar")

f == f # NoMethodError

这里出现 NoMethodError 是因为 attr_reader :name 是私有的,所以你不能访问 另一个对象 的方法 name。要启用此行为,请使用 protected

【讨论】:

以上是关于ruby 访问修饰符,不同版本的不同输出 2.5 - 2.7的主要内容,如果未能解决你的问题,请参考以下文章

Java访问修饰符

java 访问修饰符

权限修饰符

Java 访问权限修饰符 与 非访问权限修饰符

权限修饰符

四种权限修饰符