2017-05-08 43 views
2

工作在一个Ruby程序我正在寻找将一些状态数据从实例变量移动到类变量,它让我明白,虽然实例变量是自动生动的(如果你尝试阅读“没有初始化”它们,它们是自动的初始化为nil),类变量不是 - 这对我来说看起来非常不一致(与大多数Ruby语法非常一致)。Ruby类变量不会自动生成?

样例程序:

class Test 
    def id 
    @id.to_i 
    end 
    def id=(i) 
    @id = i 
    end 
    def nextid 
    self.id = id + 1 
    end 
end 

t = Test.new 
puts t.nextid #=> 1 
puts t.nextid #=> 2 

在这种情况下,调用Test::id时,如果@id没有初始化,红宝石将它自动vivify到nil(之后我to_i它获得0)。

现在我决定,我要跨Test实例共享的运行ID,所以我把它改写这样的:

class Test 
    def id 
    @@id.to_i 
    end 
    def id=(i) 
    @@id = i 
    end 
    def nextid 
    self.id = id + 1 
    end 
end 

t = Test.new 
puts t.nextid 
puts t.nextid 

应该工作一样,我想,但没有:

NameError: uninitialized class variable @@id in Test 

但这种变通办法(!?):

class Test 
    def id 
    (@@id ||= 0).to_i 
    end 
    def id=(i) 
    @@id = i 
    end 
    def nextid 
    self.id = id + 1 
    end 
end 

t = Test.new 
puts t.nextid #=> 1 
puts t.nextid #=> 2 

(当然,这样做延迟初始化为0后我可以放弃to_i,但我保持一致)。

它看起来像Ruby的理解“惰性初始化”,将其视为需要不丢NameError魔术 - 尽管||=是假想只是语法糖x = x || val(其中顺便说一句不适合INITING类变量的工作,感谢要求)。

怎么回事?

+3

'X || = val'是有点儿相当于'X || x = val',而不是'x = x || val'。另外,在你的代码中,你为什么需要一个实例方法来设置一个类变量? –

+0

你测试了哪个ruby版本?我已经尝试了ruby-2.2中的第二个例子。2,我得到了'NoMethodError:undefined method'+'for nil:NilClass'而不是'NameError:未初始化的类变量@@ id' – fangxing

+0

@fangxing:我不认为这取决于Ruby版本。我会说这是一个错误的问题。你可以使用'self.id = id + 1'来获得所提到的错误。 –

回答

3

类变量初始化

这里有一个possible explanation为什么@anil@@aNameError

但是,如果你想使用类变量,你应该初始化它们的类里面,里面没有实例方法:

class Test 
    @@id = 0 

    def id 
    @@id 
    end 

    def id=(i) 
    @@id = i 
    end 

    def nextid 
    self.id = id + 1 
    end 
end 

t = Test.new 
puts t.nextid 
puts t.nextid 

请注意,它并没有多大意义,有一个实例setter方法一个类变量。

类的实例变量

,切忌混实例方法和类变量,你可以定义在类级别与"class instance variable"一切。这是在类级别上定义的一个实例变量:

class Test 
    @id = 0 
    class << self 
    def id 
     @id 
    end 

    def id=(i) 
     @id = i 
    end 

    def nextid 
     self.id = id + 1 
    end 
    end 
end 

puts Test.id 
# 0 
puts Test.nextid 
# 1 
puts Test.nextid 
# 2 

这意味着你可以只使用attr_accesor

​​
+0

啊,我的道歉。我实际上没有读过那条线,得到了insta触发。对我感到羞耻! –

+0

“另外,你声称|| =对于类变量不起作用,但它显然是错误的” - 我没有特别声明,请阅读OP。问题是*为什么*它适用于类变量,而“先写后读”则不适用。 – Guss

+0

谢谢,但我似乎没有指出,我对解决方案不感兴趣(因为我已经提出了一个解决方案,尽管它是一个丑陋的解决方案),但更多的问题在于*为什么*事情是如此。你指出的“可能的解释”基本上归结为“在下面的边缘情况下它是有意义的”,这几乎不是设计原因。 – Guss