我试图在Ruby中创建一个延迟评估的哈希:
hash = {foo: -> {go_find_foo} }
我不希望调用者知道他们可能会获得proc
而不是值 - 理想情况下我希望Hash类获取每个获取值是否为{{1}执行它,将哈希值设置为lambda的返回值,最后将值返回给客户端。
理想情况下,我希望能够使用标准语法定义这些哈希值,如上面的代码示例所示。这意味着我无法真正使用扩展,因为我需要手动调用构造函数(proc
)。如果我进行猴子补丁,那么我就无法委托hash = LazyHash.new
的原始实现。
有什么想法吗?有没有图书馆已经这样做了?在解释[]
符号时,有没有办法告诉Ruby哪个Hash
实现实例化?
答案 0 :(得分:3)
您可以使用[]
存储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
这有一个明显的缺点,即消除了在代码库中任何地方都有Hash
或Proc
值的lambda
地图的可能性,可能会破坏Rails 。考虑使用类似refinements的内容来缩小猴子补丁的范围。
答案 1 :(得分:1)
GFD - 不确定我错过了这个:http://promise.rubyforge.org/
答案 2 :(得分:0)
Hash
构造函数可以接受一个块来计算响应。你可以用它来解决你的问题:
hash = Hash.new { |hash, key| hash[key] = "Go Fish: #{key}" }
因此,您可以创建一个继承Hash
的新类,您可以执行以下操作:
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 })
答案 3 :(得分:0)
您可以使用https://mozilla.github.io/nunjucks/api.html#customizing-syntax:
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
现在,您将在第一次搜索密钥时评估这些值。
但请注意,在您搜索密钥之前,密钥不会出现在哈希中(因为它们也会延迟添加)。