Почему локальная переменная теряет свое значение при определении метода с define_method? - PullRequest
2 голосов
/ 16 октября 2010

Попытка следовать вместе со скриншотом метапрограммирования от 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

Почему локальная переменная не сохраняется в вызовах? Чего мне не хватает, чтобы этот код работал?

Спасибо

1 Ответ

3 голосов
/ 16 октября 2010

Если вы определите локальную переменную внутри блока, она исчезнет, ​​когда будет достигнут конец блока.

Для достижения требуемого срока службы необходимо определить переменную 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
...