關於如何避免由於可變狀態引起的錯誤導致錯誤,是否存在共識?我應該如何避免在Ruby中導致錯誤?
在此示例中,緩存的結果的狀態發生了變化,因此第二次調用時出現錯誤結果。
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
可以返回dup
或clone
的@greeting_cache[formality]
greeting
可以freeze
的@greeting_cache[formality]
結果。當memoization_mutator
將字符串附加到它時,會引發異常。- 檢查所有使用
greeting
的結果的代碼,以確保它沒有任何字符串變異。
對最佳方法有共識嗎?做(1)或(2)性能下降的唯一缺點是? (我也懷疑凍結一個對象可能無法完全工作,如果它有其他對象的引用)
注意:這個問題不影響memoization的主要應用:因爲Fixnum
是不可變的,計算斐波那契數列不有可變狀態的問題。 :)
對樣式的小評論 - 您可以使用|| =運算符來簡化問候方法。像這樣:def問候(形式); @greeting_cache [形式] || = expensive_greeting_calculation(形式);結束 – zaius
@zaius:在大多數場景下都可以工作,但如果'nil'或'false'是一個有效的值,則不起作用。 –
啊,真的。我的錯。 – zaius