【问题标题】:Understanding private methods in Ruby理解 Ruby 中的私有方法
【发布时间】:2025-12-02 04:30:01
【问题描述】:
class Example
 private
 def example_test
  puts 'Hello'
 end
end

e = Example.new
e.example_test

这当然行不通,因为我们指定了明确的接收者 - Example 的实例 (e),这违反了“私人规则”。

但我无法理解,为什么在 Ruby 中不能这样做:

class Foo
 def public_m
  self.private_m # <=
 end
 private
 def private_m
  puts 'Hello'
 end
end

Foo.new.public_m

public_m 方法定义中的当前对象(即self)是 Foo 的实例。那么为什么不允许呢?要解决这个问题,我必须将 self.private_m 更改为 private_m。但是为什么会有所不同,self 不是public_m 中的 Foo 实例吗?谁是空话private_m 电话的接收者?这不是self - 实际上你省略了什么,因为 Ruby 会为你做这件事(会在 self 上调用 private_m)?

我希望我没有把它弄糊涂,我对 Ruby 还是很陌生。


编辑: 谢谢你的所有答案。将它们放在一起,我能够(最终)理解显而易见的事情(对于从未见过像 Ruby 这样的东西的人来说并不那么明显):self 本身可以是 显式和隐式接收器,这会有所不同。所以有两个规则,如果你想调用一个私有方法:self 必须是隐式接收者,并且 self 必须是当前类的实例(Example 在这种情况下 - 并且只有当 self 如果在里面时才会发生实例方法定义,在此方法执行期间)。如果我错了,请纠正我。

class Example 

 # self as an explicit receiver (will throw an error)
 def explicit 
  self.some_private_method
 end

 # self as an implicit receiver (will be ok)
 def implicit
  some_private_method
 end

 private

 def some_private_method; end
end

Example.new.implicit

给在 google 跟踪期间可以找到此问题的任何人的消息:这可能会有所帮助 - http://weblog.jamisbuck.org/2007/2/23/method-visibility-in-ruby

【问题讨论】:

  • Here 是一个非常相似的问题。

标签: ruby access-specifier


【解决方案1】:

这是短篇和长篇。 Ruby 中私有的意思是不能用显式接收器调用方法,例如some_instance.private_method(值)。因此,即使隐式接收器是 self,在您的示例中,您显式使用 self,因此无法访问私有方法。

这样想,您是否希望能够使用分配给类实例的变量来调用私有方法?不,Self 是一个变量,因此它必须遵循相同的规则。但是,当您只是在实例中调用该方法时,它会按预期工作,因为您没有显式声明接收者。

Ruby 就是你实际上可以使用 instance_eval 调用私有方法:

class Foo
  private
  def bar(value)
    puts "value = #{value}"
  end
end

f = Foo.new
begin
  f.bar("This won't work")
rescue Exception=>e
  puts "That didn't work: #{e}"
end
f.instance_eval{ bar("But this does") }

希望这更清楚一点。

-- 编辑--

我假设你知道这会起作用:

class Foo
 def public_m
  private_m # Removed self.
 end
 private
 def private_m
  puts 'Hello'
 end
end

Foo.new.public_m

【讨论】:

  • 好吧,我想我现在明白了(或者 - 我更接近于理解了 :)
  • 既然您引用了第 512 条,我希望您知道,根据允许通知侵权通知的同一小节,此类通知必须交付给相关业务的指定代理人。 AFAIK,在 Stack Overflow 上编辑答案不是法律规定的追索权。 Stack Overflow 在其法律页面上包含有用的指南和完整的联系信息。 (CYA 注意:此评论是即兴评论,仅供参考,不应被视为法律建议。)
【解决方案2】:

private 在 Ruby 中的定义是“只能在没有显式接收者的情况下调用”。这就是为什么你只能在没有明确接收者的情况下调用私有方法。没有其他解释。

请注意,该规则实际上有一个例外:由于局部变量和方法调用之间的歧义,以下将总是被解析为对局部变量的赋值:

foo = :bar

那么,如果你想打电话给一个叫foo=的作家,你会怎么做?好吧,您必须添加一个显式接收器,因为没有接收器,Ruby 根本不会知道您要调用方法 foo= 而不是分配给局部变量 foo: p>

self.foo = :bar

但是如果你想调用一个名为private 的作家foo=,你会怎么做?您不能self.foo =,因为foo=private,因此不能使用显式接收器调用。好吧,实际上对于 this 特定情况(以及这种情况单独),您可以实际上使用self 的显式接收器来调用@ 987654333@作家。

【讨论】:

  • 抹去前两句,你就有了很好的答案。你应该先说,“Ruby 中私有的定义是“只能在没有显式接收者的情况下调用”。这就是为什么你只能在没有显式接收者的情况下调用私有方法。没有其他解释。”
  • 不错的答案。如果您觉得无聊,请考虑一下:self.foo ||= bar
  • 感谢您提到作家例外。 +1,即使我对以“就是这样......”开头的答案感到不舒服。问候。
  • 我尝试用谷歌搜索 ruby​​ 论坛,看看是否有关于“为什么”的解释,最好来自 The Matz。我找不到一个。也许有更好的 google-fu 的人可以找到它。
  • 正如你所提到的,前两句话并没有真正帮助回答这个问题。我刚刚删除了它们,所以如果有人想知道这些 cmets 是关于什么的:它已经不存在了。
【解决方案3】:

这很奇怪,但是关于 Ruby 的可见性修饰符的很多事情都很奇怪。即使self 是隐式接收器,实际上将其拼写出来也会使其在Ruby 运行时的眼中是显式的。当它说不能使用显式接收器调用私有方法时,这就是它的意思,即使self 也很重要。

【讨论】:

    【解决方案4】:

    IIRC,私有方法只允许隐式接收者(当然,它总是自我)。

    【讨论】:

      【解决方案5】:

      对不起,我以前的回答。我只是不明白你的问题。

      我这样修改了你的代码:

      class Foo
       def public_m
        private_m # <=
       end
      
       def Foo.static_m
         puts "static"
       end
      
       def self.static2_m
         puts "static 2"
       end
      
       private 
       def private_m
        puts 'Hello'
       end
      end
      
      Foo.new.public_m
      Foo.static_m
      Foo.static2_m
      

      这里是实例方法的调用:

       def public_m
        private_m # <=
       end
      

      这里是类方法的调用:

       def Foo.static_m
         puts "static"
       end
      
       def self.static2_m
         puts "static 2"
       end
      
      Foo.static_m
      Foo.static2_m
      

      【讨论】:

      • 我认为你没有抓住重点。根据我对他的问题的理解,他不明白为什么使用 self.private_m 不起作用。我假设他已经习惯了让你使用 self 或 this 来调用实例方法或使用实例变量的语言。我认为他很困惑为什么使用 Self 来处理工作,而不是私有和公共访问器的工作方式。
      • 而不是创建多个答案,编辑或扩展您之前的答案。这有助于我们把事情放在上下文中。谢谢。
      【解决方案6】:

      为 User Gates 解决方案添加了一些增强功能。将私有方法调用到类方法或实例方法几乎是可能的。这是代码片段。但不推荐。

      类方法

      class Example
        def public_m
          Example.new.send(:private_m)
        end
      
        private
        def private_m
          puts 'Hello'
        end
      end
      
      e = Example.new.public_m
      

      实例方法

      class Example
        def self.public_m
          Example.new.send(:private_m)
        end
      
        private
        def private_m
          puts 'Hello'
        end
      end
      
      e = Example.public_m
      

      【讨论】:

        【解决方案7】:

        不完全回答问题,但您可以通过这种方式调用私有方法

        class Example
         private
         def example_test
          puts 'Hello'
         end
        end
        
        e = Example.new
        e.send(:example_test)
        

        【讨论】:

          最近更新 更多