2017-07-07 41 views
0

該成員循環:因爲它試圖遍歷一個類,而不是一個數組或哈希如何通過類

class Loan 
    def initialize(amount, interest) 
     @amount = amount 
     @interest = interest 
    end 
end 

loan1 = Loan.new(100, 0.1) 

Loan.each do |amount, interest| 
    debt = debt + amount + (amount*interest) 
end 

將無法​​正常工作。是否有一個迭代遍歷一個類的所有實例?

回答

5

Ruby不會自動保留對您創建的對象的引用,您有責任編寫這樣做的代碼。例如,當創建一個新的Loan實例時,您將獲得一個對象。如果你想在一流水平的each方法,你需要通過編寫捕捉他們的代碼來跟蹤這些:

class Loan 
    def self.all 
    # Lazy-initialize the collection to an empty array 
    @all ||= [ ] 
    end 

    def self.each(&proc) 
    @all.each(&proc) 
    end 

    def initialize(amount, interest) 
    @amount = amount 
    @interest = interest 

    # Force-add this loan to the collection 
    Loan.all << self 
    end 
end 

您必須手動保留這些,否則垃圾收集器會拾起並摧毀任何未提及當它們超出範圍時,它們會被放棄。

+0

在這種特殊情況下我會在第一時間收集'debt' :) – mudasobwa

+1

@mudasobwa下一步是要與貸方和借方適當的分類帳,但這已經超出了這個問題的範圍。 – tadman

1

你可以做這樣的事情:添加一些訪問器amountinterest然後使用ObjectSpace對象一起inject總結你的債務。

class Loan 
    attr_accessor :amount, :interest 
    def initialize(amount, interest) 
     @amount = amount 
     @interest = interest 
    end 
end 

loan1 = Loan.new(100, 0.1) 
loan2 = Loan.new(200, 0.1) 


debt = ObjectSpace.each_object(Loan).inject(0) { |sum, obj| 
    sum + obj.amount + obj.amount * obj.interest 
} 

debt #=> 330.0 
+0

這有一個未確定的結果,基本上是錯誤的。嘗試將'sleep(10_000)'或['GC.start'](https://ruby-doc.org/core/GC.html#method-c-start)或'loan2'創建和「債務」計算。更有甚者,一些聰明的ruby實現可能永遠不會有'loan1'和'loan2'實例化,因爲它們以後從未使用過。 – mudasobwa

+0

@mudasobwa對於哪些Ruby實現將這個代碼不起作用?你所建議的優化(死代碼修剪)不是由我知道的任何Ruby完成的,但更重要的是,我不知道如何將可能產生副作用的對象創建視爲死代碼。 –

+0

@WayneConrad將'Loan.new'的結果賦值給本地的[not used]變量不應該被認爲是副作用,但我可能是錯的。一般來說,即使現在也沒有這樣的實現,它可能很容易在明天發展,而且這些代碼會突然中斷。在紅寶石MRI中更好的GC可能會在明天打破這些代碼。這是不安全的,應該避免,因爲在Ruby規範中沒有諾言_,所創建的和未使用的對象將不會被GC'ed永遠。 – mudasobwa