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

发布于 2024-09-28 08:43:35 字数 1247 浏览 4 评论 0原文

尝试遵循 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

为什么局部变量在调用过程中不保留?为了使这段代码正常工作,我缺少什么?

谢谢

Trying to follow along with a metaprogramming screencast from pragpub and ran into some problems because of changes in Ruby since the release of screencast.

Hard to explain the problem w/o the code, so here's that:

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)

Problem: The local variable in the method memorize should only change (by taking the return value from Discounter#discount) if it is being passed different arguments than it previously was.

For example I expect the output from running the code above to look like:

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

But this is the actual output:

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

Why isn't the local variable persisting across the calls? What am I missing to make this code work?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

静赏你的温柔 2024-10-05 08:43:35

如果在块内定义局部变量,则到达块末尾时它将消失。

为了实现您想要的生命周期,您需要在块之前定义 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

If you define a local variable inside a block, it will vanish when the end of the block is reached.

To achieve the lifetime you want, you need to define the memory variable before the block:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文