在使用define_method定义方法时,为什么局部变量会失去其值?

时间:2010-10-15 20:43:04

标签: ruby methods metaprogramming

尝试跟随pragpub的元编程截屏,并因为自截屏视频发布以来Ruby的变化而遇到了一些问题。

很难解释没有代码的问题,所以这就是:

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)

问题:方法memorize中的局部变量只应更改(通过从Discounter#折扣中获取返回值),如果它传递的参数不同于以前的参数。

例如,我希望运行上面代码的输出看起来像:

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

为什么本地变量不会在调用中持续存在?为了使这段代码有用,我错过了什么?

由于

1 个答案:

答案 0 :(得分: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