我有一个对象数组:
$("#hide").addClass('dblock').removeClass('dnone')
我从原始数组创建了一个克隆来执行映射功能,然后映射到每个元素上以使其电子邮件属性变为大写:
class Person
attr_accessor :email
def initialize(email)
@email = email
end
end
array = [
Person.new('hello@gmail.com'),
Person.new('world@gmail.com')
]
它会改变原始数组。我已经尝试过clone = array.clone
clone.map { |obj|
obj.email.upcase!
obj
}
puts array.inspect # why is the original being mutated
puts clone.inspect
和dup
。和我得到相同的结果。在对每个元素的属性进行操作时,clone
为什么会突变对象?
答案 0 :(得分:3)
您克隆了包含Person
引用的 array ,但没有更改该数组;您自己更改了Person
实例。 clone
是所谓的“浅克隆”,它仅复制接收者对象,而不复制其引用可能包含的对象。
在现实世界的逻辑中:您拿了一张纸,上面写着“珍妮,蒂米”。然后将其复制到另一张纸上。然后,您拿了第一张纸,找到了它所指的人,然后给了他们一个苹果。然后,您拿了第二张纸,找到了上面的人,想知道他们的苹果来自哪里。但是只有一个蒂米,只有一个珍妮:您给第一个清单的珍妮一个苹果,第二个清单的珍妮也有一个苹果。
如果要克隆某些内容,请克隆 Jenny 。
array.map { |person|
person.clone.yield_self { |clone|
clone.email = clone.email.upcase
}
}
(请注意,我没有使用clone.email.upcase!
。原因再次是相同的原因:如果克隆对象,则它们都将为email
使用相同的字符串。{{1 }}更改该字符串,这会使克隆的电子邮件和原始电子邮件均大写。因此,我们为克隆创建了新的电子邮件字符串。)
通过使用this tool逐步进行可视化,可以最好地理解这种情况。但是,该工具运行的是Ruby 2.2,它对upcase!
不了解。该代码是等效的:
yield_self
您也可以编写此代码,尽管它无法清晰显示:
array.map { |person|
clone = person.clone
clone.email = clone.email.upcase
clone
}