Ruby - 延迟计算哈希

Ruby - Lazily Evaluated Hash

我正在尝试在 Ruby 中创建延迟计算的哈希:

hash = {foo: -> {go_find_foo} }

我不想让呼叫者知道他们可能会得到一个 proc 而不是一个值 - 理想情况下我希望哈希 class 得到每个 get 值是否是一个proc,执行它,将Hash中的值设置为lambda的return值,最后return该值给客户端

理想情况下,我希望能够使用标准语法定义这些散列,如上面的代码示例所示。这意味着我不能真正使用扩展,因为那时我需要手动调用构造函数 (hash = LazyHash.new)。如果我使用猴子补丁,那么我就不能委托给 [].

的原始实现

有什么想法吗?有没有图书馆已经这样做了?在解释 {} 符号时,有什么方法可以告诉 Ruby 要实例化 Hash 的哪个实现?

GFD - 不知道我是怎么错过的:http://promise.rubyforge.org/

Hash 构造函数可以接受一个块,以计算响应。你可以用它来解决你的问题:

hash = Hash.new { |hash, key| hash[key] = "Go Fish: #{key}" }

因此您可以创建一个继承 Hash 的新 class,然后您可以执行以下操作:

class CalculatedHash < Hash
  def initialize(rules)
    super() do |hash, key|
      hash[key] = rules.fetch(key).call
    end
  end
end

然后:

hash = CalculatedHash.new(foo: -> { go_find_foo })

您可以使用 alias_method 存储 [] 的原始实现,然后在重写的方法中引用它。

这是一个使用猴子补丁的有效实现。

class Hash
  alias_method :old_brackets, :[]

  def [](member)
    value = old_brackets(member) # Delegate to old implementation
    self[member] = value.call if value.respond_to?(:call)
    value
  end
end

这有一个明显的缺点,即消除了在代码库中任何地方使用 Proclambda 值的 Hash 映射的可能性, 可能破坏 Rails。考虑使用 refinements 之类的东西来缩小猴子补丁的范围。

您可以使用 hash block constructor:

def go_find(key)
  "shiny #{key} value"
end

h = Hash.new do |hash, key|
  hash[key] = go_find(key) if [:foo, :bar, :baz].include? key
end

h[:foo] # => "shiny foo value"
h[:quz] # => nil

现在将在您第一次搜索键时评估值。

但是请注意,在您搜索之前,键不会出现在哈希中(因为它们也是延迟添加的)。