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
这有一个明显的缺点,即消除了在代码库中任何地方使用 Proc
或 lambda
值的 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
现在将在您第一次搜索键时评估值。
但是请注意,在您搜索之前,键不会出现在哈希中(因为它们也是延迟添加的)。
我正在尝试在 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
这有一个明显的缺点,即消除了在代码库中任何地方使用 Proc
或 lambda
值的 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
现在将在您第一次搜索键时评估值。
但是请注意,在您搜索之前,键不会出现在哈希中(因为它们也是延迟添加的)。