Ruby 为什么我会得到';私有方法新&x27;仅在类方法定义内出错

Ruby 为什么我会得到';私有方法新&x27;仅在类方法定义内出错,ruby,Ruby,我有一段Ruby代码,尝试手动实现Singleton模式: class A @a = A.new def self.instance p 'initialized' @a end private_class_method :new end A.instance #=> prints 'initialized' 不幸的是,该对象将在调用.instance之前创建。为了避免这种情况,我考虑更改代码: class A @a = nil def s

我有一段Ruby代码,尝试手动实现Singleton模式:

class A
  @a = A.new

  def self.instance
    p 'initialized'
    @a
  end

  private_class_method :new
end

A.instance #=> prints 'initialized'
不幸的是,该对象将在调用.instance之前创建。为了避免这种情况,我考虑更改代码:

class A
  @a = nil

  def self.instance
    p 'initialized'
    @a ||= A.new
  end

  private_class_method :new
end

A.instance

但我得到了“为:Class(NoMethodError)调用私有方法'new'的错误”。这是非常令人费解的,为什么我在第二个例子中得到这个错误,而不是在第一个例子中?唯一的区别是在第二个示例中,在类方法定义中调用.new。我故意将private_class_方法放在底部,这样可以防止这种错误(将它放在顶部会给出两个示例的错误)。顺便说一句,我知道如果我将@a从类实例变量更改为类变量(以@@开头),这将起作用。我不明白为什么会这样,因为我知道实例变量是相对于SELF的,SELF是类,在这里我将@a初始化为nil,在SELF.instance中懒洋洋地实例化它。

这是一件奇怪的事情

A.new
不起作用,因为您应该只直接调用私有方法,所以应该使用显式
new
调用

另一方面,
new
调用类似于隐式的
self。new
但是
self。new
将引发类似
A.new
的异常。这是我不明白的奇怪部分

class A
  def self.instance
    p 'initialized'
    # ok
    new
    # should be ok but it is not
    self.new rescue p("error self.new: #{$!}")
    # should fail
    A.new rescue p("error A.new: #{$!}")
  end

  private_class_method :new
end

A.instance
# "initialized"
# "error self.new: private method `new' called for A:Class"
# "error A.new: private method `new' called for A:Class"
附言:

不能将显式接收器与私有方法一起使用


所以:

你不需要
@a=nil
。没有它,
@a=@a | | a.new
(扩展
@a | |=a.new
)右侧的
@a
是未定义的,因此将被评估为
nil
@CarySwoveland
a.new
new
的行为将不同
A.new
将引发异常,而
new
不会。问题是,
self.new
的行为应该像
new
(隐式相同),但事实并非如此!调查原因是的,在你评论之前我注意到了,这就是为什么我删除了我的评论。(我认为使用显式接收者调用私有方法总是会引发异常,这是有意义的,因为它可能是从类外执行的。)我建议您编辑,将您的解释添加到您的答案中。@CarySwoveland,是的,但是Ruby中的
new
在语义上与
self.new
相同。但看起来方法调度并不这么认为。@CarySwoveland,你实际上是对的。matterI认为Ruby不会将私有方法发送给显式接收方吗。当它看到接收者是明确的,我想它会对自己说,“如果在向其发送private
new
时,该接收器是
self
,则可以;否则我就不干了。我可以添加一些代码来检查代码执行时是否存在这种情况,但在这种情况下,只要求编码人员不要使用显式接收器会更有效。”