2016-08-02 54 views
0

比方說,我有紅寶石一類計數器,定義爲灌裝紅寶石陣列默認對象

class Counter 
    attr_accessor :starting_value 
    def initialize(starting_value) 
     @starting_value = starting_value 
    end 

    def tick 
     @starting_value = @starting_value + 1 
    end 
end 

,我想,以填補該對象的數組,使用默認的參數,如: counter_arr = Array.new(5, Counter.new(0))

這幾乎是我想要的,除了我現在有一個數組包含5次計數器的同一個實例,而不是5個新計數器的數組。即,當我運行該代碼的

counter_arr = Array.new(5, Counter.new(0)) 
counter_arr[0].tick 
counter_arr.each do |c| 
    puts(c.starting_value) 
end 

I輸出

1 
1 
1 
1 
1 

代替

1 
0 
0 
0 
0 

我想知道,什麼是 「紅寶石式的」 的方式來初始化與多個陣列對象的新實例?

+1

不要忘記像'@starting_value + = 1'這樣的語法功能。這通常不太冗長,並避免印刷錯誤。 – tadman

+1

這段代碼與'Array :: new'文檔的[「Common gotchas」部分](http://ruby-doc.org/core/Array)中的例子幾乎一致。html#method-c-new-label-Common + gotchas)它回答了這個問題。 –

回答

4

其中第一個主要障礙學習Ruby的時候,如果他們不熟悉與使用對象reverences普遍地語言的人遇到的是如何工作的。

數組是一個對零個或多個其他對象的引用的集合。這些對象不一定是唯一的,在某些情況下它們都是相同的。您在這裏創建這樣一個對象:

counters = Array.new(5, Counter.new(0)) 

這將創建一個單一的計數器對象並填充所有5個插槽,它的陣列。這是因爲方法的參數在調用方法之前被計算一次。你可以測試這個:

counters.map(&:object_id) 

返回數組中每個對象的唯一對象ID。它們將是隨機值,每個過程都不​​相同,但它們是相同的。

解決這個問題的方法是使用塊初始化:

counters = Array.new(5) do 
    Counter.new(0) 
end 

這並不插入同一個對象,但每次評估該塊的結果,並自該初始化一個新的計數器對象,對象將是唯一的。整理這件事

一種方法是調整你的Counter對象有一個理智的默認:

class Counter 
    def initialize(initial = nil) 
    @value = initial.to_i 
    end 

    def tick 
    @value += 0 
    end 
end 

這有接受任意值的優勢,即使是那些並不一定是正確的類型。現在Counter.new('2')將與該值自動轉換。這是鴨子打字的基本原則。如果它可以給你一個數字,它就像一個數字一樣好。

+0

謝謝!該代碼實際上是我寫過的前21行紅寶石,所以我很欣賞所有的改進。 – dustinroepsch

+0

希望能爲你解決。看起來你已經在跑步了,這很好看。 – tadman

+0

非常明確的答案。也許'def初始化(初始= 0); @value = initial; end'。 –

2

嘗試

counter_arr = Array.new(5) { Counter.new(0) } 
1
counter_arr = ([-> { Counter.new(0) }] * 5).map &:call 
+1

這是一個非常瘋狂的解決方案,但它至少是新穎的。 – tadman

+0

我認爲其他的答案提供了更清潔的解決方案,但我仍然對這裏發生的事情感到好奇 – dustinroepsch

+0

這是熊貓的內部答案。 – sawa