提问人:Jin 提问时间:3/25/2019 最后编辑:sawaJin 更新时间:3/25/2019 访问量:271
为什么 map 函数在对每个元素的属性进行操作时会改变对象数组?
Why does map function mutate array of objects when operating on each element's attribute?
问:
我有一个对象数组:
class Person
attr_accessor :email
def initialize(email)
@email = email
end
end
array = [
Person.new('[email protected]'),
Person.new('[email protected]')
]
我从原始数组创建了一个克隆来执行映射功能,然后我映射了每个元素以使其 email 属性变为大写:
clone = array.clone
clone.map { |obj|
obj.email.upcase!
obj
}
puts array.inspect # why is the original being mutated
puts clone.inspect
它改变原始数组。我已经尝试了两者。我得到同样的结果。为什么在对每个元素的属性进行操作时会改变对象?dup
clone
map
答:
3赞
Amadan
3/25/2019
#1
您克隆了包含引用的数组,但未更改该数组;您更改了实例本身。 就是所谓的“浅克隆”,它只复制接收方对象,而不复制它可能包含的引用对象。Person
Person
clone
在现实世界的逻辑中:你拿了一张纸,上面写着“珍妮,蒂米”。然后你把它复制到另一张纸上。然后你拿起第一张纸,找到它所指的人,并给了他们一个苹果。然后你拿起第二张纸,找到上面的人,想知道他们的苹果是从哪里来的。但是只有一个蒂米,只有一个珍妮:你给第一个列表的珍妮一个苹果,第二个列表的珍妮也有一个苹果。
如果你想克隆一些东西,就克隆珍妮。
array.map { |person|
person.clone.yield_self { |clone|
clone.email = clone.email.upcase
}
}
(请注意,我没有使用 .原因又是一样的:如果你克隆一个对象,它们都将使用相同的字符串。 更改该字符串,这将使克隆的电子邮件和原始的电子邮件都大写。因此,我们为克隆制作了一个新的电子邮件字符串。clone.email.upcase!
email
upcase!
通过使用此工具逐步完成可视化,可以最好地理解此类内容。但是,该工具运行的是 Ruby 2.2,它不知道 ;此代码是等效的:yield_self
array.map { |person|
clone = person.clone
clone.email = clone.email.upcase
clone
}
你也可以写这个,尽管它不会那么清晰地可视化:
array.map(&:clone).map { |clone|
clone.email = clone.email.upcase
}
评论
puts foo.inspect
p foo
puts foo.inspect
nil
p foo