原文地址:http://thingsinabucket.com/2015/05/27/hash_default_proc/?utm_source=rubyweekly&utm_medium=email Ruby 新手渣翻,翻得不好,烦请指正。
Hash#default_proc 是我最喜欢的 Ruby 特性之一。让我们看看它能做些什么。 有没有见过这样的代码? ###
result = {}
some_collection.map do |some_entry|
result[some_entry] = some_expensive_operation(some_entry)
end
result
不要这样写了!
除非集合中所有的值都会被使用,不然这花费不菲的计算应该被推迟到需要它的时才进行。
result = Hash.new do |hash, key|
hash[key] = some_expensive_operation(key)
end
这代码现在看起来好多了。
当找不到键的时候,Ruby将会对 Block 中的代码进行求值。这使它成为在进行这类键值查找或者快速缓存
时极好的工具。
在上期的文章中,我们知道了能通过方括号来调用Proc。当这样的操作开销太大时,只需用一个Hash来包裹
它们。
expensive_proc = ->(v) do
puts "Expensive calculation"
sleep 1
[v] * 2
end
expensive_proc_with_cache = Hash.new do |hash, value|
hash[value] = expensive_proc[value]
end
def repeat_10_times(proc)
10.times do |i|
proc[ i % 2 ]
end
end
repeat_10_times(expensive_proc) # 花费了10秒
repeat_10_times(expensive_proc_with_cache) # 花费了2秒
这是个巨大的改善!
当你调用 API 时,它一同返回了前一个与后一个的值怎么样?不用就太浪费了吧~!
paginated_lookup = ->(index) do
v = "index[#{index}]"
{
index => v,
(index + 1) => v + '.next',
(index - 1) => v + '.prev',
}
end
paginated_lookup_cache = Hash.new do |hash, key|
hash.merge! paginated_lookup[key]
hash[key]
end
paginated_lookup_cache[10] # => "index[10]"
paginated_lookup_cache[11] # => "index[10].next"
警告!
在调用 Hash#fetch 时,Hash#default_proc将不会被调用。作者很是震惊~!
times2 = Hash.new { |_, v| v*2} # => {}
times2.fetch(1) # KeyError: key not found: 1
请也不要使用这种"变通"方案。
times2.fetch(1) { |k| times2[k] }
这只是一坨翔~~~