在 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_foo
和 foo
。我需要更改什么才能使这些对象完全相互依赖?顺便也试了.dub
我假设您将值赋给 Foo#initialize
中的实例变量 @value
而不是局部变量 value
。
我还假设您没有像上面代码中那样的简单原语,而是另一个包含指针的对象,否则您很可能不会遇到这样的问题。换句话说,我假设您的 change_value
方法进行依赖于 @value
指针的操作,例如 @value[key] = some_new_value
而不是纯粹的赋值,例如 @value = some_new_object
。当使用 clone
或 dup
复制对象时,将复制该特定指针,而不是底层结构,因此对 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
因为无论如何都要复制数据,所以使用不可变对象(值对象)比某种深度克隆更通用。
我正在尝试为某个问题编写一个贪心算法。简化后看起来像这样:
有一个名为 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_foo
和 foo
。我需要更改什么才能使这些对象完全相互依赖?顺便也试了.dub
我假设您将值赋给 Foo#initialize
中的实例变量 @value
而不是局部变量 value
。
我还假设您没有像上面代码中那样的简单原语,而是另一个包含指针的对象,否则您很可能不会遇到这样的问题。换句话说,我假设您的 change_value
方法进行依赖于 @value
指针的操作,例如 @value[key] = some_new_value
而不是纯粹的赋值,例如 @value = some_new_object
。当使用 clone
或 dup
复制对象时,将复制该特定指针,而不是底层结构,因此对 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
因为无论如何都要复制数据,所以使用不可变对象(值对象)比某种深度克隆更通用。