在Ruby方法中创建缓存
Creating a cache in Ruby methods
在JavaScript中,记忆Fibonacci:这样的函数相当简单
// In JavaScript
var fibonacci = (function () {
var cache = {}; // cache for future calculations
return function (num) {
if (num < 0) throw new Error('Negative numbers not allowed');
if (num === 0) return 0;
if (num === 1) return 1;
cache[num] = cache[num] || fibonacci(num - 1) + fibonacci(num - 2);
return cache[num];
};
})();
console.log( fibonacci(5) ); // results in 5
console.dir( fibonacci ); // you can inspect the closure scope and see that the cache object saves the values for future use
我正在努力理解如何在Ruby中执行类似的操作,不幸的是,我唯一能想到的就是创建一个类并将缓存存储为类变量:
# In Ruby
class Placeholder
@@cache = {}
def fibonacci(num)
raise 'Negative numbers not allowed' if num < 0
return 0 if num == 0
return 1 if num == 1
@@cache[num] ||= fibonacci(num - 1) + fibonacci(num - 2)
end
end
example = Placeholder.new
puts example.fibonacci(5) # results in 5
我不喜欢的是,我在创建一个类结构,而我并不真正打算创建Placeholder
的实例。相反,我这样做只是因为我想将状态保存在Ruby类变量中。理想情况下,如果我能够创建一个module
并具有module
变量,那么这至少可以解决我使用基于class
的解决方案实例化的"问题"在Ruby中,你对此有什么最好的建议
根据@mealar的评论进行更新:
@可怜虫,你是在建议这样的事情吗?
class Placeholder
attr_reader :cache
def initialize
@cache = {}
end
def fibonacci(num)
raise 'Negative numbers not allowed' if num < 0
return 0 if num == 0
return 1 if num == 1
@cache[num] ||= fibonacci(num - 1) + fibonacci(num - 2)
end
end
FibonacciCalculator = Placeholder.new
puts FibonacciCalculator.fibonacci(5) # results in 5
我已经比最初的Ruby解决方案更喜欢这个了,尽管拥有Placeholder类仍然会让我感到不舒服。
当您不需要实例时,可以使用带有singleton方法的Module
:
module Fibonacci
@cache = {}
def self.series(num)
if @cache[num] then return @cache[num]; end
if num < 0 then raise 'Negative numbers not allowed'; end
if num == 0 then return 0; end
if num == 1 then return 1; end
@cache[num] = series(num - 1) + series(num - 2)
end
end
puts Fibonacci.series(5) # results in 5
请注意,对于缓存,Fibonacci
模块上的实例变量与类变量一样有效(对于某些扩展用途,它可能更好)。它之所以有效,是因为模块Fibonacci是Module
的一个实例——在这方面,它与任何其他实例变量都一样。
ECMAScript版本的直译如下:
fibonacci = -> {
cache = {} # cache for future calculations
-> num {
raise ArgumentError, 'Negative numbers not allowed' if (num < 0)
return 0 if num.zero?
return 1 if num == 1
cache[num] ||= fibonacci.(num - 1) + fibonacci.(num - 2)
}
}.()
fibonacci.(5)
# => 5
fibonacci.binding.local_variable_get(:cache)
# => {2=>1, 3=>2, 4=>3, 5=>5}
顺便说一句,我们可以做一些简化:如果num
是0
,则不返回0
,如果num
是1
,则返回1
;如果num
是0
或1
(或num <= 1
),则只返回num
。事实上,我们可以通过简单地用0
和1
的值预初始化cache
来完全消除整个条件。此外,高速缓存可以只是Array
,因为索引只是Integer
s:的连续范围
fibonacci = -> {
cache = [0, 1] # cache for future calculations
-> num {
raise ArgumentError, 'Negative numbers not allowed' if (num < 0)
cache[num] ||= fibonacci.(num - 1) + fibonacci.(num - 2)
}
}.()
有趣的是,如果我们在现代ECMAScript中写下这一点,那么这种关系就变得显而易见:
const fibonacci = (() => {
const cache = [0, 1, 1]; // cache for future calculations
return num => {
if (num < 0) throw new Error('Negative numbers not allowed');
return cache[num] = cache[num] || fibonacci(num - 1) + fibonacci(num - 2);
};
})();
console.log(fibonacci(5));
在老式的ECMAScript中,哪个会是这样的:
var fibonacci = function () {
var cache = [0, 1, 1]; // cache for future calculations
return function (num) {
if (num < 0) throw new Error('Negative numbers not allowed');
return cache[num] = cache[num] || fibonacci(num - 1) + fibonacci(num - 2);
};
}();
console.log(fibonacci(5));
当我并不真正打算创建Placeholder 实例时的类结构
好吧,这是你的问题。
Ruby是一种面向对象的语言。不能具有不属于对象的函数在对象上调用每个方法。
您应该简单地创建一个Placeholder
的实例(并给它一个合适的名称,如FibonacciCalculator
),并使缓存成为该对象上的一个简单实例变量。
您也可以使用闭包来存储缓存,这与javascript的操作方式类似。
def memoize func
cache = {}
proc do |*args|
next cache[args] if cache[args]
cache[args] = func[*args]
end
end
def slow_double x
sleep 2
x * 2
end
memoized_double = memoize(method :slow_double)
memoized_double[4] # takes 2 seconds
memoized_double[4] # returns instantly
- 创建一个类似链接的按钮,并通过Javascript函数打开一个新的弹出窗口
- 为effect Composer创建GodRays效果过程
- 从javascript创建一个列表
- onkeyup无法动态创建多个文本区域
- 如何使用javascript从主svg对象动态创建svg视图框
- 如何访问声音管理器2创建的声音对象
- 我已经创建了一个jquery转盘,并使用if条件来运行和停止转盘
- 如何创建jQuery插件来缓存jQuery对象,如下所示
- 在Ruby方法中创建缓存
- 在 javascript 中创建缓存系统
- Cakephp创建许多缓存文件
- 另一种在javascript中创建随机动态url的方法/阻止wpengine缓存
- 如何使用或从html可访问标记创建非全局javascript变量缓存
- 是否缓存了通过拉斐尔.js创建的画布元素
- 用javascript创建两次缓存图像
- 为什么要创建多个单形态缓存而不是一个多态缓存
- 停止AngularJs创建新的controller/$scope缓存,并使用已缓存的缓存
- 禁用动态创建的Javascript缓存
- 我如何创建一个“;清除高速缓存”;按钮
- 是否有可能缓存客户端动态创建的文件