【问题标题】:Why won't Ruby allow me to specify self as a receiver inside a private method?为什么 Ruby 不允许我在私有方法中将 self 指定为接收者?
【发布时间】:2012-06-04 10:25:36
【问题描述】:

Ruby 作为一种面向对象的语言。这意味着无论我发送什么消息,我都会严格将其发送到类的某个对象/实例上。

例子:

 class Test
   def test1
    puts "I am in test1. A public method"
    self.test2
   end

   def test2
    puts "I am in test2. A public Method"
   end
 end

有道理我在 self 对象上调用方法 test2

但我不能这样做

  class Test
   def test1
    puts "I am in test1. A public method"
    self.test2 # Don't work
    test2 # works. (where is the object that I am calling this method on?)
   end

   private
   def test2
    puts "I am in test2. A private Method"
   end
 end

test2public method 时,我可以在self 上调用它(很公平,一个发送给self 对象的方法)。但是当test2private method 时,我不能自己调用​​它。那么我发送方法的对象在哪里?

【问题讨论】:

  • 但是在这两种情况下你都可以在没有self.的情况下调用test2
  • 这在 Ruby 2.7 中已更改,如果 test2 是私有的,现在也允许 self.test2。详情请见my answer

标签: ruby private public


【解决方案1】:

这已在 Ruby 2.7(2019 年 12 月)中进行了更改:self.foo() 现在对私有方法 foo 也有效。

参考资料:

【讨论】:

    【解决方案2】:

    我发送方法的对象在哪里

    它是self。如果您不指定接收者,则接收者为self

    Ruby 中private 的定义是私有方法只能在没有接收者的情况下调用,即使用self 的隐式接收者。有趣的是,puts 方法根本不会打扰您,它也是一个私有实例方法;-)

    注意:此规则有一个例外。只要接收者是self,私有设置器可以通过显式接收者调用。事实上,它们必须使用显式接收器调用,否则局部变量赋值会产生歧义:

    foo = :fortytwo      # local variable
    self.foo = :fortytwo # setter
    

    【讨论】:

    【解决方案3】:

    问题

    在 Ruby 中,不能通过显式接收器直接调用私有方法; self 在这里没有得到任何特殊待遇。根据定义,当您调用 self.some_method 时,您将 self 指定为显式接收者,因此 Ruby 说“不!”

    解决方案

    Ruby 对其方法查找有规则。规则可能有更规范的来源(除了转到 Ruby 源),但 blog post 在顶部列出了规则:

    1) Methods defined in the object’s singleton class (i.e. the object itself)
    2) Modules mixed into the singleton class in reverse order of inclusion
    3) Methods defined by the object’s class
    4) Modules included into the object’s class in reverse order of inclusion
    5) Methods defined by the object’s superclass, i.e. inherited methods
    

    换句话说,私有方法首先在 self 中查找,而不需要(或允许)显式接收器。

    【讨论】:

      【解决方案4】:

      self 表示您所在对象的当前实例。

      class Test
        def test1
          self
        end
      end
      

      调用 Test.new.test1 将返回类似于 #<Test:0x007fca9a8d7928> 的内容。
      这是您当前使用的 Test 对象的实例。

      将方法定义为私有意味着它只能在内部当前对象中使用。
      使用self.test2 时,您将在当前对象之外(获得实例)并调用该方法。
      所以你正在调用一个私有方法,就好像你不在对象中一样,这就是为什么你不能。

      当您不指定 self 时,您将留在当前对象内。
      所以你可以调用该方法。 Ruby 足够聪明,知道test2 是一个方法而不是一个变量,并且可以调用它。

      【讨论】:

      • 但是它看起来太程序化,只写方法名称而不明确提及接收者。
      猜你喜欢
      • 2021-07-20
      • 1970-01-01
      • 2014-11-03
      • 2017-08-10
      • 2013-11-12
      • 2011-10-09
      • 1970-01-01
      • 2022-01-19
      • 2014-03-01
      相关资源
      最近更新 更多