2010-10-15 20 views
2

試圖跟隨從pragpub進行元編程屏幕截圖,並且由於截屏視頻發佈後Ruby的變化而遇到了一些問題。爲什麼使用define_method定義方法時局部變量會失去它的值?

說不清的問題W/O的代碼,所以這裏的是:

class Discounter 
    def discount(*skus) 
    expensive_discount_calculation(*skus) 
    end 

    private 

    def expensive_discount_calculation(*skus) 
    puts "Expensive calculation for #{skus.inspect}" 
    skus.inject {|m, n| m + n } 
    end 
end 

def memoize(obj, method) 
    ghost = class << obj; self; end 
    ghost.class_eval do 
    define_method(method) do |*args| 
     memory ||= {} 
     memory.has_key?(args) ? memory[args] : memory[args] = super(*args) 
    end 
    end 
end 

d = Discounter.new 
memoize(d, :discount) 

puts d.discount(1,2,3) 
puts d.discount(1,2,3) 
puts d.discount(2,3,4) 
puts d.discount(2,3,4) 

問題:的方法記憶局部變量只能改變(從折扣#折扣取返回值)如果它傳遞的參數不同於以前的參數。

例如我希望從上面運行代碼的輸出看起來像:

Expensive calculation for [1, 2, 3] 
6 
6 
Expensive calculation for [2, 3, 4] 
9 
9 

但是,這是實際的輸出:

Expensive calculation for [1, 2, 3] 
6 
Expensive calculation for [1, 2, 3] 
6 
Expensive calculation for [2, 3, 4] 
9 
Expensive calculation for [2, 3, 4] 
9 

爲什麼不在本地變量持續在呼叫?我錯過了什麼讓這個代碼工作?

感謝

回答

3

如果你定義一個塊中的局部變量,到達塊結束時,它就會消失。

達到你想要的壽命,你需要的塊之前定義memory變量:

def memoize(obj, method) 
    memory = {} 
    ghost = class << obj; self; end 
    ghost.class_eval do 
    define_method(method) do |*args| 
     memory.has_key?(args) ? memory[args] : memory[args] = super(*args) 
    end 
    end 
end 
+0

啊廢話。我也知道這一點。老實說,我甚至沒有注意到我已經用塊來定義這個變量了。感謝您幫助我認識到我忽視的先生:) – 2010-10-15 20:50:23

相關問題