在 Ruby 中复制没有任何指针的对象

Copy object without any pointers in Ruby

我正在尝试为某个问题编写一个贪心算法。简化后看起来像这样:

有一个名为 Foo 的对象,它具有一个名为 value 的随机属性和一个以依赖于整数 input 的方式更改此值 change_value 的方法

class Foo
  def initialize
    value = rand(1,10)
  end

  def change_value(input)
    #changes the value in a certain way
  end
end

现在,贪心算法只为所有可能的输入获取 Foo 的新 value 和 return 最好的 input.

foo = Foo.new

best_value = 0
best_input = 0

(1..inputs).each do |k|
  temp_foo = foo.clone
  temp_foo.change_value(k)
  if temp_foo.value>best_value
    best_value = temp_foo.value
    best_input = k
  end
end

Foo.change_value(best_input)

代码几乎按预期运行。最大的问题是每个函数中的 change_value 方法改变了 temp_foofoo。我需要更改什么才能使这些对象完全相互依赖?顺便也试了.dub

我假设您将值赋给 Foo#initialize 中的实例变量 @value 而不是局部变量 value

我还假设您没有像上面代码中那样的简单原语,而是另一个包含指针的对象,否则您很可能不会遇到这样的问题。换句话说,我假设您的 change_value 方法进行依赖于 @value 指针的操作,例如 @value[key] = some_new_value 而不是纯粹的赋值,例如 @value = some_new_object。当使用 clonedup 复制对象时,将复制该特定指针,而不是底层结构,因此对 temp_foo.change_value 的任何调用都会导致对 [=21= 的更改]的底层证券@value.

为避免这种情况,您需要复制 @value 引用的对象。正如 this post 中所讨论的,有一个技巧可以与 Marshal 一起使用,但我建议不要使用它,因为它会导致大量开销。相反,我会定义一个 deep_dup 方法,如下所示:

class Foo
  def deep_dup
    # Either this
    @value = @value.dup

    # OR this, and define the method #deep_dup in the class of @value 
    # to dup its internal structure too:
    @value = @value.deep_dup
  end
end

然后 temp_foo = foo.clone 改为 temp_foo = foo.deep_dup.

我认为#clone 或#dup 不起作用,因为它们将在 Foo 中共享对@value 的引用。

无论如何,您可以通过更改 Foo#change_value 来提高可读性,这样它实际上不会改变对象,而是 returns 一个副本:

class Foo
  def initialize(value = nil)
    @value = value || rand(10)
  end

  def change_value(input)
    # returns a new Foo instance
    Foo.new(@value + 1)
  end

  def value
    @value
  end
end

因为无论如何都要复制数据,所以使用不可变对象(值对象)比某种深度克隆更通用。