【问题标题】:Recursive call with private method in Ruby在 Ruby 中使用私有方法进行递归调用
【发布时间】:2014-11-17 03:28:30
【问题描述】:

为什么这段代码有效?我知道private 用作方法的修饰符,使用显式接收器 (self) 将不起作用。

我知道会有SystemStackError,但我想了解可见性的概念。

class Methods
    private
    def private_method
        puts "I'm in private method"
        self.private_method
    end
end
class ChildMethods < Methods
    def private_method
        super
    end
end
ChildMethods.new.private_method

【问题讨论】:

  • Methods#private_method 是私有的这一事实有点牵强附会。 ChildMethods#private_method 导致 Ruby 将 private_method 发送到父类中的 self。哪个private_method?它首先查看self 的班级中是否有一个。 self 是什么?当然,它是ChildMethods 的一个实例(如果不确定,请在Methods#private_method 中添加puts 语句),因此Ruby 找到并执行ChildMethods#private_method,将其发送回父级。顺便说一句,self.private_method 中的self. 没有添加任何内容,因为如果不是明确的,则假定接收者是self

标签: ruby recursion methods private


【解决方案1】:

您有两个private_method 方法,一个在超类中(即私有),一个在子类中被覆盖(即公共)。

您的代码有效,因为超类中的self.private_method 没有调用它自己的私有private_method,而是调用子类中的公共private_method

例如,这将不起作用:

Methods.new.send(:private_method)

【讨论】:

  • 它是如何工作的?为什么它调用的是子类方法而不是它自己的方法?
  • 这就是它每次的工作方式:当您调用self 上的方法时(显式或隐式),方法查找将始终从最具体的子类开始,并向上工作超类/模块,直到找到它。在您的情况下,private_method 立即在 ChildMethods 中找到(这是一种公共方法)。
  • 对,但是如果我在方法类中创建了一个调用 private_method 的 public_method,这将在 self.private_method 上崩溃,因为如果我进行此调用,我将直接站在方法类上:方法.new.public_method
  • 对,因为在Methods 上,该方法是私有的,您不能显式调用私有方法。这就是为什么我在回答中指出Methods.new.send(:private_method) 不起作用。
  • 没错,它会打印一次:“我在私有方法中”然后它会失败
【解决方案2】:

不能为 explicit 接收器调用私有方法,但可以为 implicit 调用一个,就像你一样。换句话说,一个对象可以调用 -other object- 超类私有方法,因为它存在于它自己的上下文中。

由于没有明确的接收者,这也可以正常工作

  1 class Methods
  2     private
  3     def private_method
  4         puts "I'm in private method"
  5         private_method
  6     end
  7 end
  8 class ChildMethods < Methods
  9     def public_method
 10       private_method
 11     end
 12 end
 13 ChildMethods.new.public_method

但这会引发错误,因为self 是一个显式接收器。

  1 class Methods
  2     private
  3     def private_method
  4         puts "I'm in private method"
  5         self.private_method # <-------------------------
  6     end
  7 end
  8 class ChildMethods < Methods
  9     def public_method
 10       private_method
 11     end
 12 end
 13 ChildMethods.new.public_method

Press ENTER or type command to continue
I'm in private method
1.rb:5:in `private_method': private method `private_method' called for #<ChildMethods:0x00000101084290> (NoMethodError)
        from 1.rb:10:in `public_method'
        from 1.rb:13:in `<main>'

这也很好用:

  1 class Methods
  2     private
  3     def private_method
  4         puts "I'm in private method"
  5         self.public_method # <-------------------------
  6     end
  7 end
  8 class ChildMethods < Methods
  9     def public_method
 10       private_method
 11     end
 12 end
 13 ChildMethods.new.public_method

【讨论】:

  • 你的意思是当我从 ChildMethods 调用时,我已经设置了调用者的“上下文”,当我再次调用 private_method 时,它会向下传递给孩子并再次调用它?因为我所处的环境。
  • 基本上是的。 它将传递给孩子 - 它接受自我,并发送消息。如果您没有指定接收者,它使用“隐式接收者”方式使用当前上下文发送消息,并且这种方式调用方法不会考虑消息可见性方面。
猜你喜欢
  • 2021-11-07
  • 1970-01-01
  • 2014-03-23
  • 2011-08-07
  • 1970-01-01
  • 1970-01-01
  • 2010-09-30
  • 2013-04-14
  • 2023-04-10
相关资源
最近更新 更多