【问题标题】:Why does a local variable lose its value when defining a method with define_method?为什么使用define_method定义方法时局部变量会丢失其值?
【发布时间】:2010-10-15 20:43:04
【问题描述】:

试图跟随来自 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#discount 获取返回值)。

例如,我希望运行上述代码的输出如下所示:

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

为什么局部变量不在调用中持续存在?为了使这段代码正常工作,我缺少什么?

谢谢

【问题讨论】:

    标签: ruby methods metaprogramming


    【解决方案1】:

    如果你在一个块内定义一个局部变量,它会在到达块的末尾时消失。

    要达到你想要的生命周期,你需要在block之前定义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
    

    【讨论】:

    • 啊,废话。我也知道。老实说,我什至没有注意到我已经用块定义了那个变量哈哈。感谢您帮助意识到我忽略了先生:)
    猜你喜欢
    • 2014-09-20
    • 2015-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-23
    • 2015-05-16
    • 1970-01-01
    相关资源
    最近更新 更多