2009-10-10 14 views
13

請原諒總newbiew問題,但爲什麼@game_score總是零?總新手:在Ruby中的實例變量?

#bowling.rb 

class Bowling 
    @game_score = 0 
    def hit(pins) 
     @game_score = @game_score + pins 
    end 

    def score 
     @game_score 
    end 
end 
+2

這是Java的方式,歡迎紅寶石:d – khelll 2009-10-10 18:56:00

回答

37

讓我們通過代碼,我們應?

#bowling.rb 

class Bowling 
    @game_score = 0 # (1) 

此時(1),我們還在Bowling內。請記住:類只是其他任何對象。因此,此時您將0分配給類對象Bowling的實例變量@game_score

def hit(pins) 
    @game_score = @game_score + pins # (2) 

現在(2),我們是Bowling類的實例方法內部。 I.e .:這是一種將屬於Bowling實例的方法。所以,現在實例變量@game_score屬於Bowling類的實例,而不屬於類本身。

由於這個實例變量初始化從來沒有任何東西,它會評估爲nil(在Ruby中,未初始化的變量永遠評估爲nil),所以這個計算結果爲@game_score = nil + pins,自nil沒有一個#+方法,這將導致NoMethodError異常被引發。

end 
def score 
    @game_score # (3) 

在這裏,(3),我們又是Bowling類的實例方法內。這將始終評估爲nil,因爲我上面列出的理由:@game_score從未初始化,因此它的計算結果爲nil

end 
end 

我們可以使用Ruby的反射能力,看看這是怎麼回事:

p Bowling.instance_variable_get(:@game_score) # => 0 
b = Bowling.new 
p b.instance_variable_get(:@game_score) # => nil 

現在讓我們注入一個值到實例變量:

b.instance_variable_set(:@game_score, 1) 
p b.score # => 1 
b.hit(3) 
p b.score # => 4 

所以,我們看到一切正常,我們只需要弄清楚如何確保實例變量被初始化。

要做到這一點,我們需要編寫一個初始化方法。奇怪的是,初始化方法實際上是一個私人的實例方法,稱爲initialize。 (之所以initialize是實例方法,而不是一個類的方法,其實很簡單的Ruby拆分對象創建在兩個階段:。內存分配和對象的初始化內存分配由方法來完成所謂的alloc和對象初始化是由實例執行方法調用initialize(Objective-C程序員會認識到這一點)alloc是一個類方法的原因很簡單,就是在這個執行過程中沒有實例,而且initialize是一個實例方法是對象初始化顯然是每個對象。爲方便起見,有一個叫new標準廠房類方法調用都allocinitialize你。)

class Bowling 
def initialize 
    @game_score = 0 
end 
end 

讓我們來測試這一點:

c = Bowling.new 
p c.score # => 0 
c.hit(2) 
p c.score # => 2 

BTW:只是一些輕微的紅寶石風格提示:縮進2個空格,而不是1個標籤。而你的hit方法更慣用@game_score += pins

16

因爲你沒有

def initialize 
    @game_score = 0 
end 

類定義的分配沒有做什麼你認爲它是幹什麼的,當hit被調用它不能添加到nil做。

如果您現在詢問發生了什麼事@game_score,好吧,永遠記得類是一個對象對象是一個類

Ruby類有這種類似禪宗的「真實」存在的方式很酷。 Ruby並不完全具有命名類,相反,類名是對類Class的對象的引用。通過在實例方法的外部分配@game_score,您創建了一個類實例變量,該類對象的一個​​屬性爲Bowling,它是類Class的一個實例。這些對象通常不是很有用。 (參見第1章,Ruby之道,哈爾富爾頓。)

9

@game_score定義有被稱爲類實例變量,這對於單例類對象中定義的變量:

class << Bowling 
    attr_accessor :game_score 
end 

Bowling.game_score #=> 0 

這是因爲您可以區別於爲實例對象定義的正常的實例變量

0

@game_score將永遠不會得到一個零值在這裏 - 你需要把它裏面初始化,如

高清初始化 @game_score = 0 結束