8

ミュータブルな状態によるバグの原因となるメモ化を回避する方法についてコンセンサスはありますか?

この例では、キャッシュされた結果の状態が変更されたため、2 回目に呼び出されたときに間違った結果が返されました。

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

これを回避するために私が見ることができるアプローチは次のとおりです。

  1. greetingdupまたはcloneのを返すことができます@greeting_cache[formality]
  2. greetingfreezeの結果でした@greeting_cache[formality]memoization_mutatorこれにより、文字列を追加するときに例外が発生します。
  3. の結果を使用するすべてのコードをチェックしてgreeting、文字列の変更を行っていないことを確認してください。

最善のアプローチについてコンセンサスはありますか? (1) または (2) を行うことの唯一の欠点は、パフォーマンスの低下ですか? (また、他のオブジェクトへの参照がある場合、オブジェクトの凍結が完全に機能しない可能性があると思います)

補足: この問題は、メモ化のメイン アプリケーションには影響しませんFixnum。:)

4

2 に答える 2

4

私は複製されたオブジェクトを返すことに傾倒します。新しい文字列を作成することによるパフォーマンスへの影響はほとんどありません。また、フリーズすると実装の詳細が明らかになります。

于 2011-01-13T08:22:59.373 に答える
0

私はまだ 'ruby 初心者' であり、文字列に対する '<<' メソッドと '+' メソッドの違いを認識していたかどうかはわかりません。

first_person = "Bob"
puts(greeter.greeting(:casual) + " " + first_person) # => Hi Bob
second_person = "Sue"
puts(greeter.greeting(:casual) + " " + second_person) # => Hi Sue

# str << obj → str
# str + other_str → new_str
于 2014-10-09T10:37:32.797 に答える