如何避免备忘录导致Ruby中的错误? [英] How should I avoid memoization causing bugs in Ruby?
问题描述
关于如何避免由于易变的状态而导致记忆不足的错误,是否达成共识?
Is there a consensus on how to avoid memoization causing bugs due to mutable state?
在此示例中,缓存的结果的状态发生了变化,因此第二次调用时给出了错误的结果.
In this example, a cached result had its state mutated, and therefore gave the wrong result the second time it was called.
class Greeter
def initialize
@greeting_cache = {}
end
def expensive_greeting_calculation(formality)
case formality
when :casual then "Hi"
when :formal then "Hello"
end
end
def greeting(formality)
unless @greeting_cache.has_key?(formality)
@greeting_cache[formality] = expensive_greeting_calculation(formality)
end
@greeting_cache[formality]
end
end
def memoization_mutator
greeter = Greeter.new
first_person = "Bob"
# Mildly contrived in this case,
# but you could encounter this in more complex scenarios
puts(greeter.greeting(:casual) << " " << first_person) # => Hi Bob
second_person = "Sue"
puts(greeter.greeting(:casual) << " " << second_person) # => Hi Bob Sue
end
memoization_mutator
我可以避免的方法是:
-
greeting
可能返回@greeting_cache[formality]
的dup
或clone
-
greeting
可以freeze
@greeting_cache[formality]
的结果.当memoization_mutator
向其附加字符串时,会引发异常. - 检查所有使用
greeting
结果的代码,以确保它们均不对字符串进行任何突变.
greeting
could return adup
orclone
of@greeting_cache[formality]
greeting
couldfreeze
the result of@greeting_cache[formality]
. That'd cause an exception to be raised whenmemoization_mutator
appends strings to it.- Check all code that uses the result of
greeting
to ensure none of it does any mutating of the string.
关于最佳方法是否达成共识?做(1)或(2)降低性能的唯一缺点是吗? (我还怀疑冻结一个引用了其他对象的对象可能无法完全起作用)
Is there a consensus on the best approach? Is the only disadvantage of doing (1) or (2) decreased performance? (I also suspect freezing an object may not work fully if it has references to other objects)
旁注:此问题不会影响记忆的主要应用:由于Fixnum
是不可变的,因此计算斐波那契序列不会有可变状态的问题. :)
Side note: this problem doesn't affect the main application of memoization: as Fixnum
s are immutable, calculating Fibonacci sequences doesn't have problems with mutable state. :)
推荐答案
我倾向于返回克隆的对象.创建新字符串对性能的影响几乎没有.冻结会公开实现细节.
I would lean towards returning a cloned object. The performance hit of creating a new string is next to nothing. And freezing exposes implementation details.
这篇关于如何避免备忘录导致Ruby中的错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!