无需 Marshal 帮助创建对象深拷贝的方法
Methods to create deep copy of objects without the help of Marshal
我有 3 个简单的 classes CashRegister、Bill 和 Position。 CashRegister 由 Bill 对象组成,Bill 对象由 Position 对象组成。它们的实现方式如下
class CashRegister
def initialize
@bills = []
end
def clone
#?
end
end
class Bill
def initialize(nr)
@nr = nr
@positions = []
end
def clone
#?
end
end
class Position
def initialize(product, price)
@product = product
@price = price
end
def clone
#?
end
end
如何创建可以深度复制这些 classes 对象的方法。不允许使用 Marshal.load(Marshal.dump(an_obj))
。
编辑:到目前为止我得到了这个:
class CashRegister
def initialize
@bills = []
end
def clone
@bills.map { |bill| bill.clone}
end
end
class Bill
def initialize(nr)
@nr = nr
@positions = []
end
def clone
cloned = super
cloned.positions = @positions.map{ |pos| pos.clone}
cloned
end
end
class Position
attr_reader :preis
# this method is given
def produkt
@produkt.clone()
end
def initialize(product, price)
@product = product
@price = price
end
def clone
cloned = super
cloned.product
cloned
end
end
class位置的克隆方法似乎没问题(没有编译错误)。但是class Bill中的那个有错误,它说“未定义的方法'positions=',所以问题一定在cloned.positions = @positions.map{ |pos| pos.clone}
行。但是我不明白,可以'我们不是这样称呼 cloned.positions
吗?
这只是您需要担心的实例变量。
class Position
attr_accessor :product, :price
def initialize(product, price)
@product = product
@price = price
end
end
p1 = Position.new("lima beans", 2.31)
#=> #<Position:0x000000027587b0 @product="lima beans", @price=2.31>
p2 = Position.new(p1.product, p1.price)
#=> #<Position:0x0000000273dd48 @product="lima beans", @price=2.31>
我们可以确认p2
是p1
的深拷贝。
p1.product = "lettuce"
p1.price = 1.49
p1 #=> #<Position:0x0000000271f870 @product="lettuce", @price=1.49>
p2 #=> #<Position:0x000000026e9e00 @product="lima beans", @price=2.31>
p2.product = "spinach"
p2.price = 2.10
p1 #=> #<Position:0x0000000271f870 @product="lettuce", @price=1.49>
p2 #=> #<Position:0x000000026e9e00 @product="spinach", @price=2.1>
如果 class 定义如下(其中 products
是一个数组),则情况会更复杂。
p1 = Position.new ["carrots", "onions"]
#=> #<Position:0x000000025b8928 @products=["carrots", "onions"]>
p2 = Position.new p1.products
#=> #<Position:0x000000025b0048 @products=["carrots", "onions"]>
p1.products << "beets"
p1 #=> #<Position:0x000000025b8928 @products=["carrots", "onions", "beets"]>
p2 #=> #<Position:0x000000025b0048 @products=["carrots", "onions", "beets"]>
p2
不是我们想要的。我们需要写
p1 = Position.new ["carrots", "onions"]
#=> #<Position:0x00000002450900 @products=["carrots", "onions"]>
p2 = Position.new p1.products.dup
#=> #<Position:0x0000000243aa88 @products=["carrots", "onions"]>
(注意.dup
)所以
p1.products << "beets"
#=> ["carrots", "onions", "beets"]
p1 #=> #<Position:0x00000002450900 @products=["carrots", "onions", "beets"]>
p2 #=> #<Position:0x0000000243aa88 @products=["carrots", "onions"]>
更一般地说,我们需要对实例变量进行深拷贝。
另一个可能的答案是使用 full_dup gem(完全公开,由我编写)然后简单地使用:
p2 = p1.full_dup
现在 full_dup,与常规 dup 一样,不复制任何单例方法。如果这很重要,请尝试 full_clone gem(是的,我也是)。
如果有需要从复制(或克隆过程)中排除的字段,可以定义可选的full_dup_exclude(或full_clone_exclude)方法来列出要从中排除的字段处理中。
请注意,无需担心尝试克隆对象中可能存在的数字、符号和其他不可克隆的内容。 gems.
安全地处理了这些
这个解决方案有效
class CashRegister
attr_accessor :bills
def initialize
@bills = []
end
def clone
cloned = super
cloned.bills = @bills.map { |bill| bill.clone }
cloned
end
end
class Bill
attr_accessor :positions
def initialize(nr)
@nr = nr
@positions = []
end
def clone
cloned = super
cloned.positions = @positions.map{ |pos| pos.clone }
cloned
end
end
class Position
attr_reader :price
attr_writer :product
# this method is given
def product
@product.clone
end
def initialize(product, price)
@product = product
@price = price
end
def clone
cloned = super
cloned.product = product
cloned
end
end
我有 3 个简单的 classes CashRegister、Bill 和 Position。 CashRegister 由 Bill 对象组成,Bill 对象由 Position 对象组成。它们的实现方式如下
class CashRegister
def initialize
@bills = []
end
def clone
#?
end
end
class Bill
def initialize(nr)
@nr = nr
@positions = []
end
def clone
#?
end
end
class Position
def initialize(product, price)
@product = product
@price = price
end
def clone
#?
end
end
如何创建可以深度复制这些 classes 对象的方法。不允许使用 Marshal.load(Marshal.dump(an_obj))
。
编辑:到目前为止我得到了这个:
class CashRegister
def initialize
@bills = []
end
def clone
@bills.map { |bill| bill.clone}
end
end
class Bill
def initialize(nr)
@nr = nr
@positions = []
end
def clone
cloned = super
cloned.positions = @positions.map{ |pos| pos.clone}
cloned
end
end
class Position
attr_reader :preis
# this method is given
def produkt
@produkt.clone()
end
def initialize(product, price)
@product = product
@price = price
end
def clone
cloned = super
cloned.product
cloned
end
end
class位置的克隆方法似乎没问题(没有编译错误)。但是class Bill中的那个有错误,它说“未定义的方法'positions=',所以问题一定在cloned.positions = @positions.map{ |pos| pos.clone}
行。但是我不明白,可以'我们不是这样称呼 cloned.positions
吗?
这只是您需要担心的实例变量。
class Position
attr_accessor :product, :price
def initialize(product, price)
@product = product
@price = price
end
end
p1 = Position.new("lima beans", 2.31)
#=> #<Position:0x000000027587b0 @product="lima beans", @price=2.31>
p2 = Position.new(p1.product, p1.price)
#=> #<Position:0x0000000273dd48 @product="lima beans", @price=2.31>
我们可以确认p2
是p1
的深拷贝。
p1.product = "lettuce"
p1.price = 1.49
p1 #=> #<Position:0x0000000271f870 @product="lettuce", @price=1.49>
p2 #=> #<Position:0x000000026e9e00 @product="lima beans", @price=2.31>
p2.product = "spinach"
p2.price = 2.10
p1 #=> #<Position:0x0000000271f870 @product="lettuce", @price=1.49>
p2 #=> #<Position:0x000000026e9e00 @product="spinach", @price=2.1>
如果 class 定义如下(其中 products
是一个数组),则情况会更复杂。
p1 = Position.new ["carrots", "onions"]
#=> #<Position:0x000000025b8928 @products=["carrots", "onions"]>
p2 = Position.new p1.products
#=> #<Position:0x000000025b0048 @products=["carrots", "onions"]>
p1.products << "beets"
p1 #=> #<Position:0x000000025b8928 @products=["carrots", "onions", "beets"]>
p2 #=> #<Position:0x000000025b0048 @products=["carrots", "onions", "beets"]>
p2
不是我们想要的。我们需要写
p1 = Position.new ["carrots", "onions"]
#=> #<Position:0x00000002450900 @products=["carrots", "onions"]>
p2 = Position.new p1.products.dup
#=> #<Position:0x0000000243aa88 @products=["carrots", "onions"]>
(注意.dup
)所以
p1.products << "beets"
#=> ["carrots", "onions", "beets"]
p1 #=> #<Position:0x00000002450900 @products=["carrots", "onions", "beets"]>
p2 #=> #<Position:0x0000000243aa88 @products=["carrots", "onions"]>
更一般地说,我们需要对实例变量进行深拷贝。
另一个可能的答案是使用 full_dup gem(完全公开,由我编写)然后简单地使用:
p2 = p1.full_dup
现在 full_dup,与常规 dup 一样,不复制任何单例方法。如果这很重要,请尝试 full_clone gem(是的,我也是)。
如果有需要从复制(或克隆过程)中排除的字段,可以定义可选的full_dup_exclude(或full_clone_exclude)方法来列出要从中排除的字段处理中。
请注意,无需担心尝试克隆对象中可能存在的数字、符号和其他不可克隆的内容。 gems.
安全地处理了这些这个解决方案有效
class CashRegister
attr_accessor :bills
def initialize
@bills = []
end
def clone
cloned = super
cloned.bills = @bills.map { |bill| bill.clone }
cloned
end
end
class Bill
attr_accessor :positions
def initialize(nr)
@nr = nr
@positions = []
end
def clone
cloned = super
cloned.positions = @positions.map{ |pos| pos.clone }
cloned
end
end
class Position
attr_reader :price
attr_writer :product
# this method is given
def product
@product.clone
end
def initialize(product, price)
@product = product
@price = price
end
def clone
cloned = super
cloned.product = product
cloned
end
end