2017-05-08 46 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