为什么 self.method_name 无法访问私有方法?其中只有 private method_name 可以在任何方法中访问 ruby​​ 中的私有方法

San*_*ede 2 ruby

class Person
  def one
    @var = 99
    self.two
  end
  private
  def two
    p @var
  end
end
p=Person.new
p.one
Run Code Online (Sandbox Code Playgroud)

当我运行此代码时,我收到错误 main.rb:4:in one': private method Two' Called for #<Person:0x00000000965a28 @var=99> (NoMethodError)
from main.rb:12:in `'

class Person
  def one
    @var = 99
    two
  end
  private
  def two
    p @var
  end
end
p=Person.new
p.one
Run Code Online (Sandbox Code Playgroud)

当我运行这个时,我得到的输出为 99。因此,当 p.one 调用时,它会转到方法一,当它找到没有任何接收者对象的方法二时执行它(这意味着方法二将 self 作为对象)并且成功执行该方法。

但是当我手动给出 self.two 时,它给了我错误,为什么?

两个 VS self.two 的方法调用有什么区别?

Jör*_*tag 5

\n

为什么 self.method_name 无法访问私有方法?

\n
\n

因为这就是private定义方式,至少在您使用的旧版 Ruby 中是这样。

\n

在当前版本的 Ruby 中可以您所描述的行为仅存在于旧版本的 Ruby 中。

\n

如果我使用我的 Ruby 安装(由 YARV 3.0.0 实现的 Ruby 3.0.0)运行您的代码,我不会收到错误。

\n

以下是历史上private的定义:

\n
\n

方法private只能在没有接收者的情况下被调用。

\n
\n

例如,请参阅ISO/IEC 30170:2012信息技术 \xe2\x80\x94 编程语言 \xe2\x80\x94 Ruby规范的第 13.3.5.3 节私有方法

\n
\n

私有方法不能用显式接收者调用,即,如果方法调用中与方法接收者对应的位置出现主表达式链式方法调用,则不能调用私有方法

\n
\n

但请注意,这并不是故事的全部。

\n

在此规则下如何调用私有属性编写器?答案是:不能!您不能使用,self.foo = bar因为不允许您使用显式接收器,并且您不能使用,foo = bar因为这是对局部变量的赋值foo,而不是对属性 writer 的调用foo=

\n

所以,这个规则实际上有一个例外:

\n
\n

一个private方法只能在没有接收者的情况下被调用,除非它是一个属性编写者,那么它也可以用一个接收者来调用,接收者就是字面量伪变量self

\n
\n

请注意,它必须是字面量伪变量self。它不能是计算结果为同一对象的任意表达式

\n

即这是允许的:

\n
self.foo = bar\n
Run Code Online (Sandbox Code Playgroud)\n

但这不是:

\n
this = self\nthis.foo = bar\n# private method `foo=\' called for #<\xe2\x80\xa6> (NoMethodError)\n
Run Code Online (Sandbox Code Playgroud)\n

ISO Ruby 语言规范的确切文本是:

\n
\n

私有方法不能用显式接收者调用,即,如果方法调用中与方法接收者对应的位置出现主表达式链式方法调用,则不能调用私有方法,方法除外调用以下任意形式,其中Primary-Expressionself-Expression

\n
    \n
  • 单一方法赋值
  • \n
  • 缩写方法赋值
  • \n
  • 单索引分配
  • \n
  • 缩写索引分配
  • \n
\n
\n

然而,这仍然不能解决所有问题:运算符怎么样,例如self + baror !self?名称为保留字的方法怎么样class

\n

拟议的规则变得越来越复杂。要获得一些见解,请参阅以下有关 Ruby 问题跟踪器的讨论:\n Bug #9907使用 private attr_writer/进行缩写方法分配attr_reader不起作用。[免责声明:我是提交该错误的人。]

\n

为了使这项工作正常进行,您必须将规则更改为类似的内容

\n
\n

一个private方法只能在没有接收者的情况下被调用,除非它是一个属性编写器或一个操作符,那么它也可以使用一个接收者来调用,该接收者是字面量伪变量self,包括在缩写的方法赋值中。

\n
\n

正如您所看到的,规则变得相当复杂。

\n

提出了一个更简单的规则,现在从 Ruby 2.7 开始实现:

\n\n

现在的规则是:

\n
\n

private只能在没有接收器或使用显式接收器(即文字伪变量)的情况下调用方法self

\n
\n

您可能会问自己,为什么不使用这个更简单的规则呢?

\n
\n

方法private只能通过接收者来调用self

\n
\n

原因是旧规则、中间规则和新规则都可以静态地决定,事实上甚至可以在语法分析时决定,而这个非常简单的规则则不能。

\n