2014-11-02 45 views
2

我有这样的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 

我得到“私有方法的新“呼吁':类(NoMethodError)”的错误,但。这非常令人费解,为什么我会在第二个例子中得到这个错误,而不是第一个呢?唯一的区别是在第二个例子中.new在类方法定义中被调用。我故意将private_class_method放在底部,这样可以防止这种错误(将它放在最上面会给出两个示例的错误)。顺便说一句,我知道这将工作,如果我把@从一个类实例变量更改为一个类变量(以@@开头)。我不明白为什么这会工作,因为我知道实例变量是相对于SELF和SELF是类,无论是我初始化@a到零和我懒惰实例化它self.instance。

+0

你不需要'@a = nil'。没有它,'@a = @a ||右侧的'@ a' A.new'('@a || = A.new'的扩展)未定义,因此将被评估为'nil'。 – 2014-11-02 16:12:54

回答

1

这是一件奇怪的事情。

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" 

PS:http://weblog.jamisbuck.org/2007/2/23/method-visibility-in-ruby

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

SO:Understanding private methods in Ruby

+0

@CarySwoveland'A.new'和'new'行为会有所不同。 'A.new'会引发异常,而'new'则不会。问题是'self.new'应该像'new'一样(它隐含地是相同的),但它不会!调查为什么是这样的 – fl00r 2014-11-02 16:20:29

+0

是的,我注意到你评论之前,这就是为什么我删除了我的评论。 (我认为用明确的接收者调用私有方法总是会引发异常,这是有道理的,因为它可能是在课堂外完成的。)我建议您编辑以将解释添加到答案中。 – 2014-11-02 16:22:10

+0

@CarySwoveland,是的,但Ruby中的'new'语义上与'self.new'相同。但看起来方法调度并不这么认为。 – fl00r 2014-11-02 16:31:05

相关问题