【问题标题】:How should I avoid memoization causing bugs in Ruby?我应该如何避免记忆导致 Ruby 中的错误?
【发布时间】:2011-06-08 05:44:00
【问题描述】:

对于如何避免由于可变状态而导致记忆错误的共识?

在此示例中,缓存结果的状态发生了变化,因此在第二次调用时给出了错误的结果。

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. greeting 可以返回 dupclone@greeting_cache[formality]
  2. greeting 可以是 freeze 的结果 @greeting_cache[formality]。这会在memoization_mutator 向其附加字符串时引发异常。
  3. 检查所有使用greeting 结果的代码,确保没有任何代码对字符串进行任何修改。

是否就最佳方法达成共识?做(1)或(2)的唯一缺点是降低性能吗? (我还怀疑如果对象引用了其他对象,冻结对象可能无法完全工作)

旁注:这个问题不影响记忆化的主要应用:由于Fixnums 是不可变的,计算斐波那契数列不存在可变状态的问题。 :)

【问题讨论】:

  • 关于风格的小评论 - 您可以使用 ||= 运算符简化问候方法。像这样:def greeting(formality); @greeting_cache[形式] ||= 昂贵的问候计算(形式);结束
  • @zaius:这在大多数情况下都有效,但如果 nilfalse 是有效值,则无效。
  • 感谢您的接受。很糟糕,我们在这里没有得到更多的讨论。也许是因为没有其他方法了 :) 如果您想出更好的解决方案,请更新我。
  • @zaius:也许有一天我会开始赏金。

标签: ruby state memoization


【解决方案1】:

我倾向于返回一个克隆的对象。创建新字符串对性能的影响几乎为零。冻结会暴露实现细节。

【讨论】:

    【解决方案2】:

    我还是 '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
    

    【讨论】:

    • 感谢您的建议,但我更喜欢更通用的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 2020-06-06
    • 2021-08-02
    • 1970-01-01
    • 2017-01-20
    • 1970-01-01
    • 2023-03-04
    相关资源
    最近更新 更多